diff --git a/light-client/src/client.rs b/light-client/src/client.rs index e1cd8b9..d024043 100644 --- a/light-client/src/client.rs +++ b/light-client/src/client.rs @@ -407,17 +407,17 @@ mod test { #[test] fn test_success_update_client_epoch() { - let header = hex!("0a222f6962632e6c69676874636c69656e74732e7061726c69612e76312e48656164657212d3460ab2110aaf11f908aca0dfd0c915ed6e3bf10aab0e202dfb47a446eec66bd209be1254deea2551cf94d4a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942465176c461afb316ebc773c61faee85a6515daaa0d673cb388003076ea9d177df010d633f8a781d8a07a2d39abf4dee7f4f66560ca09310e9d727791dd64c1b9a82137fcd84d30d72db5cb9612954c4e4aaac371bb6a0b2014756b40d764f128315cd9d884f74cc09e4338266edd2a7b59877abff8a6fb9010006a002cae2c09472216150d68116104e2258428914810601284a01001a6d558ea2511130184c8005cd211bf8001a6678c8190258d082221221802412142dea20464859422b420c208144c08ab64024b57170032142164a502094100682400402ccec90338b2331e344418a8003104db1baeeb63b002bf4241648b43aeb090ca26d7ed90181033b49a89934004a528a081ca406c96d211c9e885101c017c21624171048200e458b12135607cc028004f1486a82501000d643816148233880383cb4a254e22025484252d04083911272696eb064609168001441135137bb48f2589438ca8b91e48c002b7602c606018385730480e060b4e04815aa2755d9b37448028401eab9c88408583b0083e5723e846516824cb906add88301020b846765746888676f312e31392e38856c696e7578000000b19df4a2150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e912d4c407bbe49438ed859fe965b140dcf1aab71a993c1f7f6929d1fe2a17b4e14614ef9fc5bdc713d6631d675403fbeefac55611bf612700b1b65f4744861b80b0f7d6ab03f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d2569c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca72b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739e2d3a739effcd3a99387d015e260eefac72ebea1956c470ddff48cb49300200b5f83497f3a3ccb3aeb83c5edd9818569038e61d197184f4aa6939ea5e9911e3e98ac6d21e9ae3261a475a27bb1028f140bc2a7c843318afd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd98cbf822e4bc29f1701ac0350a3d042cd0756e9f74822c6481773ceb000641c51b870a996fe0f6a844510b1061f38cd0f8b5831df7ffb86082f8e61d76df2c3ef83424fa67ec8876d449b2fd44df70c68424f2fda1b5a577fd90d189e4b4c9c5d9c81d99fd9fb074081f89eb6c6c3a624af63e6ab774a39be3f91c2bf914687a185671f331820de9ac6cb6b1739b1d13c1374a5f020959c6f84c8401eab9c6a03a2a7732ae0dc866b2d586a161d8d4558fd4f1f0069c8e1d8cc54c2f6cab57648401eab9c7a0dfd0c915ed6e3bf10aab0e202dfb47a446eec66bd209be1254deea2551cf94d48094a0f11205eb4f01d1998f9ce7392e3043fb81cc84eb261457a71cd31ceb85307e27d5e12e7da1bacaf574ed1090636046b47d74916b049a60700f488c2751f701a00000000000000000000000000000000000000000000000000000000000000000880000000000000000800a9d060a9a06f90317a0389ad325ba54c2b20796e7ef348c0cfd043d0e47dc5d36f493cc6ff15551a5cfa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942d4c407bbe49438ed859fe965b140dcf1aab71a9a08cd020e09c663281b9ae955b0687ae330aae132fad7ccc3c19b1e783f9852b62a058179c401509bc10ac5dfb63292d5f0dddf83f62ecbace571381e5eba88a20cfa0b55ae3ad5ed5842f99c9872cb5fa9a63f66c541489ca91620010eb54d35af568b901005e64027388ded758a9406cedc31cdd7a8ed041c1fcd83c707cbfb51a4468ab16a6863b506121f18b83b300b6e75e9b10ef0f1e3908732ae4f0480056c02c5ac547d028dc8b71306a9979f4c8eda035bc659d33a5c8c43ac62115045fc0cbbc31d3beadf70e2703d5d527c114cb6ead19abea85cda8abe56030f8b67bda080d35b25c7ee432b1484bced5b4435779a88c44a5c7df78663c0ab3d032ca45ef1876b23b811252f7af4882550fcf9b8e9839c4798c39b3829d83da2d61212b8e4228efe29fcaac2ed8561ba05484aae3d7a52c577f45d58b1d351fbc54e6f750efb353d2d41cd1d9cb9c653338b2430861437a2094b1f5fa4e483eb841ddfa294858028401eab9c98408583b0083e69429846516824fb90118d88301020b846765746888676f312e31392e38856c696e7578000000b19df4a2f8b5831df7ffb860ae76b8e45de3d46d3e3f1adc47057430c7d71df79f2e554772f68776c0b6e85eb786ddde8c731e3c7b46a63fca05507c00b482e0f67b0bf5361c840ec33c54a90fc290051dcdb4feb242c56787dd1184412980c029859a36ebefd639a026954ff84c8401eab9c7a0dfd0c915ed6e3bf10aab0e202dfb47a446eec66bd209be1254deea2551cf94d48401eab9c8a0389ad325ba54c2b20796e7ef348c0cfd043d0e47dc5d36f493cc6ff15551a5cf80a7bac79aa62ed6b91415c9400db3fa59d4528af80ac203de536f20e5c2f9fc7143bee31e43d0d46ef49d4f99dffa6dd34254ca88f9cc60c1a3a50891614daef601a00000000000000000000000000000000000000000000000000000000000000000880000000000000000800a9e060a9b06f90318a022c32b836e14bb6b733e91900715e7268b23efbe462314fbc500d36b425ba104a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347943f349bbafec1551819b8be1efea2fc46ca749aa1a06ecdc699ec13310359ca3d1bd7e507020bc4063490ec16f1881dd5cc81ea6da9a0e739535837bc8c327cb65e0aa1a3d8c9a1a1844cbdfb2c60fb6ff861995606f6a07034ff88e282a64345d3e1b654a94504a6225063b61fb014807f1cd82e6610b5b90100c63676c23fc2565ad4d90272974d1c0e92da75e191390e2ced5ec91234c8f917c77c9a35614051886b6379a0041f13938ec75df905aa3664ca687b56f52c27c27c42c68e2d7c2db9f75bb4bbe666ac3e64b67b2a475636b7a775943f837f4d04840cbe2e0a2e298541cf98c03ca55bfb7c5908ffa929c4a6f77bfe5d034e50e58efbb16502f538a69fce26ba3516c88dc6b647e16deb053bb715bec43fd09873a7f34c9b72a79feb14240eefbf86759c4cebdff98ca1be8d1ed951b72de52363e697577b3d453fd693d607abca67f03860f7034415a8981d9f97dc76f350fe96b3f8d45577be6f9231372fa2e33ac5837024b4fb3b6ecfdad6e80d811bebdd79028401eab9ca8408583b0084013b95b08465168252b90118d883010209846765746888676f312e32302e36856c696e7578000000b19df4a2f8b5831df7ffb860973510b65d5f1f134b71d4e204275e5229d31646c0c63051b7e7cbf7b2a37e3634cab526336cc6da768a2e14fd8d5db613def7689f1b7c74b12a8794e836c74b1bfbc0e138bdd6dcc3de1d3f0313203fed1c97032b3c110c976e3cba4683ea8ff84c8401eab9c8a0389ad325ba54c2b20796e7ef348c0cfd043d0e47dc5d36f493cc6ff15551a5cf8401eab9c9a022c32b836e14bb6b733e91900715e7268b23efbe462314fbc500d36b425ba1048053391cf629f049537a52461a20a370c48fedc2e74d9269baf7a3877ee808c9da0c580de4ac77495d864920da762169ea1f92e7cf52e889103cb0a8405a6850ec01a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080120510c7f3aa0f1a951df90e92f90211a06dd75d98e90634b3bb5291f8c14498a0d772e62a78e82de5097a4da0d4060e41a08f088073f331f27c28eda5cbd298eaa12f2f2d4d529dd31402cb4febaeb88478a04b46786e5a83fde3763bceee958e672a4d182850b5a91f38226e9385ae69d3eba06ff3cb8143314fe846a546abbee661a73f4eeefc0b9d56cda7cd2637ed57ca42a0393bc2437ba742be234d313c29fcfd3de0c798f816cef35988217f9c985397daa0626b3d47b7c1519007cca079ea93c2dcaba6c2a4ba4e5b650588a0d6f845a7d4a0f5eb17977ba1709050d9c6c808c37df2296c4a766b8d09c6ed3be1355878f8c1a0ae60112553477fb4eb97a61f3ca2d7988c2fd5af1dc6056a1c9fd1975124e27aa059a015a82f1ba917ea2c847a791f1ffe45db6bf8ec12be0e7558544f190a71bfa0c0652ad14aa94acdf3a58f8090debe5ab11d6619e1a58d7c37a5f9c91839b171a024e93d32d68f50ab4ce9201db50ee803ec748bcfd0f0926fc1e6792e998cdd98a0612438ff57632a7cedad3b77e17584ed293d08433793bbe76ea5879f38ff6b70a06a64f953601cff261b74892d3db2f19e8832fee7ed2051a9d36e80d4aa163d97a0d9db99411ebc74c356f1385f867a8ebb79693e8910d4ab81a26b53a6999961b5a0514d3230b3d239fc1f9243c03bb1f6c75cae112605118479e46994a7a3a32140a02d71605c614c583284d7aee4e6f123c2e7db894fc5b655076114f588a1f2aa2280f90211a07f9d3901b46ee6b732d2aaaf84d40b47ebc831ed47adb8a2c1c43613de4605dba0877a5df00fd7b24640adba5bba8d39aa3da551cd9aa7ef6268d133f966ee3853a056389b7c71cf708a9f104ab69ea97c8f8561c94fd3cdf1c69026c552c624d826a0af67e75eb2f83ef984dad98b2e2d05a1b9e0d18175e7882e9ceb847c994f89a9a038eae492cbea3819225dc47e9e674ae67152a4a622434aca0f511048bd4e2882a0545ca391120d092d590f710ce97d747b4b10efc5fe71304890bb78d83ad971cda0867c657413b8318047ea92cbb77cf3deacfc656c1f5169121c28f794e5af26bba09bb21e93ca6bbfe9a956aa45cb206c1ba30b9238bae608d9e61a85c3a1484698a01b39a4dd4376819599fd8a99a5844233e92747ab47d03af7c7428151d78140f7a08418b9718f62e572bb0ef05748a66dba2017dc4ccc947712e40c58e05ca7ee0da083afe7ac216b0a694e59d64d4b674fa496d9145f4426510308c3afbabc6e6390a031cdb81e4d4e346ba20be533add17ae14f020e3c75b1d942ceb831b4463d5429a06458dc8f9eec70fe541af826f608ec29f196568904a98159f4082ad0b194e864a0939d9a2627cde2638d815e8dab37856e2769741e130a96d5fe6dd02932a8394da089f290235af65e72b8976c726c070c2923c650f74344699f3b34658a6630d199a0299c63b050cf559312ff256ab0466948d67230e719ee2bc3189c5bc89c28d84580f90211a0e6d6c23fa1734c2f5d243a3cfb0f39cd02cfbfdb4bc3c8f431aed32fcd2854dda0bd9e04a6c8916365dec12c4d12f14e63d680afc5db3316bb69f6d3ffff20d52aa0f753573922dd3666bd8c5dbd5b4ce6de8a8f0800188c034d383d8916a53ce3efa091e6a46980bb716301891e6d65c420b2c25481f5f1fc0ec3e921fa1ec0b33e65a07ea284e90799149edd33ace9e67e83806405f98028558b45a5dcf6e411ac1d7ba070c2688533f8337332f5c7c11b1bd46704b7f2937d4683e509ca40cfb97502eda04b03a777f36dc9be61cca125223359ebb167562b64715f8aada6ee9f0219df0da093993ee43f49f3e33f6cb6541c6393dca4ac240893f1c0a250490f784d138814a0f47f2f96f3597ce60ca3370a8fbcbbac7d5b55bab33c29eb1fd3b386bcb6a2fba099de7a7a033931dc6ac0f61b83fdf182aa296cb2a8239a0cc6dbb313c47157a8a0e56b7c7c4656dd0b9f0919e09d6da771d38c453af4c0f0d6544f390fd2a543f7a081cca9739d3140249d6ae461371ff7b465883352d81bc757ca982f52d524c1dba0d3dbf7dcc484d241e77ee2be684b262f614f871a8c9d6598430a2134973782e0a09917ddd6820b6c66429eba999f5030141508a439dea8393b098035dbd283c287a0e053ba6f7c0865df751aa1b868b6dab4f49bba166c64e86762abb1e6556e5bdfa0c8af8672c865cd5af89c4a6b9e55b87f1dcf1ee0f76560a7d1f3c04daab60e4e80f90211a043beb9ae278028ab0e6ae1dd97bfc1adc7da5d5b35418cde1372ed15dc60d844a0969897f77040974812fdc243499998d5a2f808b010e3e743fff5bb1cf06701b7a072a62f95c81d3849bc02102bcb66b5be775ad3b68cae7967451e6a13c48b6c43a0488199752a3a18aaaaa52b07d5a306826c4ccb2afe3cb30058de3e361dee74cfa0a63fb5ff17b1ca7f9c095cd9a888f4fd493a3379cdc2a0cfb49353c854923fc7a0ce7a2593ac4b8c89ad4c5fde8940d9695e969cfe6eb6a614954a48bcfd715843a0cb8b4d0264778a2ab04b96777ffe78a5ee62483a87446fceccb37813cda25b60a008fac15554b1c384ad91aa696e7e5e5454dc0c0fa343bb26b48a4f34ec95f785a0f1811154dd01ffd9f43443acd407e0beee53bbd03f40f63b7d993681182f0289a0a620126c5db0919a29b4b27c728dc42d2d63015849527be64acd0062b575c0eea088d3cde1a49a0ac95f076d1e15b3fde9cefd0f7e308f53b3aa466eb0385aec50a07f99a989d621bd1b59fa51d109f6413c9cb7f8ccd704dbf13cfb27bebec8f1b1a04321111d914057fe87d18e8c6f4128c6c7778fa2b73d435f0b2562c5910361a2a07ee88a697a560dc7023a840f16df54c599dc345e787927bf6628963e782a6847a078d58eb776d8d9dd6dbdbdd830b0350bd0427b15678ef457da5d41ec2cca708ca050e0c4585785b9c800e24c4c4e00599d7e5c4e6d8f3363979ab6c49ed514f12680f90211a011ff0a2d404fd7ed97509ebaa806f2a5ba09c5cde5ff596903c4313783487509a014931c578b05f5948939281aa31d2bc8b05b01c6932c45bf7a70972a430575c2a07272592f567daa667135799961e9eef529a6cd754395e39694d9452ae24a8797a092b17ad714173ec4787f0b3b9d2dfa96680861e093b5121441ffcde64183d074a06db41a6efb6f94c7d185f76deb8bb00468715bf6828fb63db31b880a6050c54da07ce695737ab0d4bf9003a06ce83b11e75d81fbeb47c013b41f9c2e00a97cb87aa0dfe63771f833e98a5aeff54d9dd5a8dcfd89ca43c23644b18ec8e29ab8ccc287a0a327c817dc8a8ea3a5d3ca3cb55169777a1bfa30fe9f0df842eb3978dbd6737ba053683114bdaed7819b30ab8baec1fb9a2a96fee4dabc72f319cec9869da3b0b0a04d98297a896312d18da40240ed9a527f4c01c73edd3ea1f7c28338d1d863d97ca070451b5f2a402b497659eb18e648ac46f39c0068cc91436eb0b082b1d06dd63da066e866f800200512b0d3e534c547f4d2012429152cc9693bf1553cc22361627ba003fc4e648aafdadd7a9fa7cb534103f08dc699413ecda22bda46898bfb792429a0b46a167c66b50c74227d03a68971e124fdd011d6c90f5a08f6fe30ae34de603ca0a7ced66271235bc27b154f37bee6d9a1366cd253176c96de707d124fcc593c35a0f4f09b104a86cefc5c282d393b415e6c224eb8a463386448ebebfad9f9f53c9680f90211a05f93540f4317a4c6d8b73556a7ffdab6fcf0aa36af84b8c4bd2a3e7114e2da4ea05dd8c13b1b83485911f5e1185669f7d5559c260193a72e52597a3e80736c248ca03d50a67e8ec93696c35865d9f03814e95406c8d04e5decc320b9a24e5beee1baa0a928e2ea8773ba69dde5344d69069b237667dbaaa69e86133d4e444e432799b1a0ebb2cbf0c3314ddf681f21a29fa17b320094684ba35e725bc36bbc407821cfa3a0762aeb8161d2b1b8a5ee51d1ede36f51cc2dad7e0c4d0ff097b89c831aff8c35a0957a8eaaac924688482d21a95b7a7f01889ab39a7a50d58efaaffa9e486ae071a046c10b0c15aa83973ea4b108f50bad2638941550fce7c9308c8b968abee271f8a08a831384faa68f9caa047a6200464e11cfe5f9f700a5ed9435e5241d9d2a501ca020630d0f41d1f38c61fc8d3fc6170f6f11fc52ade454930a3b5e4f4491b47467a04539a99793f29484fdbd39b606f27265499acb3c24461f48858655f07166f0dfa05fd40548cfae17d12e103db98572f22cdc8dd3ec670be570727a7ff68f6bce9fa032efe866f058f79ef06de75f682e10773576eb9fca3f950fda96ea9926784685a05c170d685d29417781f678b746174c7500e7c228b4bd71bcfe9f5421742a0b67a0c3fb71b77522f06c4a4e4cb7029e7faeb747b8e446460586ea0d5e9abae68cd9a03f2294bf8bea287c7afafde4b39aaa56716230ef425ece688f6a78fcadf5f49e80f9013180a0c2cb770a3d18eb1214a782cc81b79a7fd772716c2d050ef66011095c3774e8f7a08fc7d7da06fba7ffa69b095aae41147e3a55b89644682057cedab705ba7aefd5a05975b434f69398107a4d1729f8f56e75247df09c65b1a750797818607bf118df80a026cea4c13260b2a1dd74bb6fcc7cc36162d2856ce691a36165c633ba68f7b783a0f7b0c667509a4ce937c487b45bc53c0700543daf4f8c127fbe475b4e1084d2328080a0454eca3fcc32afd4c4000ccbb47732bbce342b1a9d374fb5872162f2c873625fa0b3e6c44579a731cc730a5472e83c6098fa2943e5b2c72f4475f0afea76848a87a03b8c951788b8c93366aedbf88f6c1ca6085cd0249025ce542f19294b40bb92f180a0a10cfa51ae290afebd64a5b530db7088fa0b02f22ce9b0838135b422b885dee5808080e482000ea07b2632b8b97e159d88f112a8dd9d44df2f3c4502e0c79a29297ea7f61f41f311f851a030590b16841225b9590cdc95b19176201d442ca0b931c6e4314d20a1c772ea9ba052e8f9f247cd159c65b304863d444087f6a60d7dbec3a0e4fa09f007b5a1c64f808080808080808080808080808080f86c9c20120c458c4c09a9448628f84e81161b308d5c4041a3d3a1ea329d0eb84df84b0487400e8b4f1c9c00a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4702a440bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2a4412d810c13e42811e9907c02e02d1fad46cfa18bab679cbab0276ac30ff5f198e5e1dedf6b84959129f70fe7a07fcdf13444ba45b5dbaa7b1f650adf8b0acbecd04e2675b2a442465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c8162a442d4c407bbe49438ed859fe965b140dcf1aab71a993c1f7f6929d1fe2a17b4e14614ef9fc5bdc713d6631d675403fbeefac55611bf612700b1b65f4744861b80b0f7d6ab02a443f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a2a4461dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d252a4470f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba72a4472b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a512a447ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e2a448b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d788694852a44a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b7412a44b4dd66d7c2c7e57f628210187192fb89d4b99dd40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a44be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cd2a44cc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a4192a44d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce7392a44d93dbfb27e027f5e9e6da52b9e1c413ce35adc11b313f9cba57c63a84edb4079140e6dbd7829e5023c9532fce57e9fe602400a2953f4bf7dab66cca16e97be95d4de70442a44e2d3a739effcd3a99387d015e260eefac72ebea1956c470ddff48cb49300200b5f83497f3a3ccb3aeb83c5edd9818569038e61d197184f4aa6939ea5e9911e3e98ac6d212a44e9ae3261a475a27bb1028f140bc2a7c843318afd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a44ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c1921832a44ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5b2a44ef0274e31810c9df02f98fafde0f841f4e66a1cd98cbf822e4bc29f1701ac0350a3d042cd0756e9f74822c6481773ceb000641c51b870a996fe0f6a844510b1061f38cd0").to_vec(); - let height = 32160200; - let trusted_height = 32160199; + let header = hex!("0a222f6962632e6c69676874636c69656e74732e7061726c69612e76312e48656164657212b2520ab3110ab011f908ada0c1b3a1b35c53d9860d1464d20138e6271602e00ea876757d7106016ce83466f3a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ef0274e31810c9df02f98fafde0f841f4e66a1cda0db01e241c7ed90c7fafad6ebbd727b14b7633bd336a97fc9761bc37b12aad0f4a0cc1257fae1a1a2648190df64c111671f764e7729157d87a6a75046060e937d53a0791ba98205dc99116e137099424fe843a0765cb96f82d2c597a43da570355351b9010003b2fbb5134f56fe987ffbd6bf693df76b135948febbc7f808dea7f70e3a59a2d7f8bdeed8263f57c7d336fd0bdf3ff9df186a1e557df4edd987f8fefeafa6f0e4f385ed7df6bffd57c1d75f5a8e95fe7ff45b2588f66cfc8affdfd4decc77d8f6feb97f2ad701308ff50f677fe79af5ae4cd4fae8c7ed0cd7fdcc3cd0d3feaf976ec2daebddaa766d8d9e689ff7f7bfbf646fa72897dfcedff9b57bf9cb1ff1e378ca85df3607bcaf2b65dc7fc68dfefe3f1ea73cfff9174ad7e82f73ed7ff3e4a09f9fd97d794777aadfecdbcb77bf7b7ffcbbdff4615c4314fbfedb6ff68959f3fa71efdcd44bff3e6f44b655e388bfd4bcf8fa11a95f67fbfff8eb2af9cd028402211e008408583b0084011b48aa8465ba3192b906add883010307846765746888676f312e32302e35856c696e757800000001a091a0150bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e912d4c407bbe49438ed859fe965b140dcf1aab71a993c1f7f6929d1fe2a17b4e14614ef9fc5bdc713d6631d675403fbeefac55611bf612700b1b65f4744861b80b0f7d6ab03f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d25685b1ded8013785d6623cc18d214320b6bb647598a60f82a7bcf74b4cb053b9bfe83d0ed02a84ebb10865dfdd8e26e7535c43a1cccd268e860f502216b379dfc9971d35872b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d788694859bb832254baf4e8b4cc26bd2b52b31389b56e98bab764a39ff81dad720d5691b852898041a3842e09ecbac8025812d51b32223d8420e6ae51a01582220a10f7722de67c1a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b741b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de7b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419ce2fd7544e0b2cc94692d4a704debef7bcb61328b64abe25614c9cfd32e456b4d521f29c8357f4af4606978296c9be93494072ac05fa86e3d27cc8d66e65000f8ba33fbbd1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce739e2d3a739effcd3a99387d015e260eefac72ebea1956c470ddff48cb49300200b5f83497f3a3ccb3aeb83c5edd9818569038e61d197184f4aa6939ea5e9911e3e98ac6d21ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5bef0274e31810c9df02f98fafde0f841f4e66a1cd98cbf822e4bc29f1701ac0350a3d042cd0756e9f74822c6481773ceb000641c51b870a996fe0f6a844510b1061f38cd0f8b5831bdbffb860a1b2529dc7c1cb57e9b80a29d82ca0fafad5245fb7947158cc585b96609a8dfd005f2b9d111cad1d663d506cfc8a2cd2111831cb0863c5a92007a91dc504a32e496d6e3e392258e7fd47d0ed7e01a8448a1f9967fae814829c4104b2d2f27b9df84c8402211dfea0567d4dd0ea048881bb924343a4e69bd8164a03ab881739dd0ce5cde9c3ab13408402211dffa0c1b3a1b35c53d9860d1464d20138e6271602e00ea876757d7106016ce83466f380e863967543e27479ee79f33ab2ee5e276b0970a1565d96767e3ff55ab16ce0ac421983faa09eea6aa8e769fdf8182251e9225e39b3feef23a302ba897c41d20c01a00000000000000000000000000000000000000000000000000000000000000000880000000000000000800a9e060a9b06f90318a029bf36156df8e525f809db876705baae274b69205fd5716448392648e0941c52a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794295e26495cef6f69dfa69911d9d8e4f3bbadb89ba06f43ef7855ea56f036992abd7d992004d9fb11c0f16ac7efad79698cfd468c55a048f43cb851c8a35dcaaa6216f8f041da9e548f6b699b3b60bd095409044c4542a0f5ca7a7a61593ea62df7e100ea541399629e3f3f90975ae4127c2cf46670f029b90100f93e770a65dbd3dedfe67ddcfad59d7bdc5ca5259f7eb5bd97efe35b4667e55aee7cdd8bf2715d8b3baf7dbbd73fa3b3d11fd1790ebaece8ad723bd8c3bce78837acd76ef9e95c7cd5ecfffb97a21ff6b8f4a8f52af4687b60d65c6fbff7de78cfeed676fa37efb75effed979f5ceaec3cdefe7b4babee0f8a69e6f7de4ed8a5bbdafe8753ae8eef77cb363f7f7415bcfef79cfd35a7943e3b783fd2d9eb35ff6f7cd6b2b7cda77a7eefe6beff8725f1e7eb35dbd4f2b59e976768eaf7ff5e64f0f73fb2ccfd449ec7ebdfa6eff77333f5bfb7efcabe75beb7d2ff73e4b5ef1863f5a0333644d9f307f777fededc8199fd0eef6bbf5c1e7cf2afdfd9bf7f14a9028402211e018408583b00840108e73c8465ba3195b90118d983010307846765746889676f312e32302e3133856c696e7578000001a091a0f8b5831bdbffb860a79e04e92307a88aacdb97e1af9c99826690c90dc3fb83251f6506c48fb5a8c515ab7afc554408fa67b4251b9910545601d47524cd356d2c7a6cf23e7a857666a3ca20c7b26949815d00ad110a57486afb03ebbdc0e6ad6205efda248580eafff84c8402211dffa0c1b3a1b35c53d9860d1464d20138e6271602e00ea876757d7106016ce83466f38402211e00a029bf36156df8e525f809db876705baae274b69205fd5716448392648e0941c52800290f15f352f1012037a54e82bc7fcef239ba9bb867286089a287d100ecd737449b93ff0af15c13affebd5db2a6be4767192689e8bcc809b26b794d9a37468ec00a00000000000000000000000000000000000000000000000000000000000000000880000000000000000800a9d060a9a06f90317a024897fb02565f515fa9fbb541eae07a132473349842b34786a06ec2a0d6ea64ea01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347942d4c407bbe49438ed859fe965b140dcf1aab71a9a0175af0ef466ba120d773ebb4e5cf28141d94efd6214e5bb9cde6ef206a3afbfda066cc81edf1fbd1f605d108d2b478fbe7bb0c38ee3e3e5650ae035efa563fd729a0e3431ac6ae4eee634fd6a1d6e45807789b94ea432bdf8f9f857545823798e824b901008e7ea3b3105f95d18ca860548c85a7efd518cfa69c238dbd4efebd9d241b25f1cc559715d455a3e533b036ad819aa6b19b695ea91c3b23cebd293dd0b2b6e0ec56458b681fe22f7d45eec13f82ae55b2eaf5fe7537677a8ab6641be7f43100c09eccb83e9a8fa79e8f2f853d47b34bdb194d8c61c8fb2e6f6af59c3ac658b8460f6bc24c028e2ac09b88ef42a9028cc03a3577c9af93d67beccf3771457b0bfa92d2112a9be46b607ebdc9e67a14dd0d6ebd1cf9c48b7738a67744b114f952d5a1227fc312292cce5ca1aea7c48a1830bbc5e00a95c934fbf350d5d69ea1ed3edfb3bd79b9c95528a33546f781dfebbc6056911153b0887ce359ef1c8ac9181a028402211e028408583b0083f9c3198465ba3198b90118d983010307846765746889676f312e32302e3132856c696e7578000001a091a0f8b5831bdbffb860a5654b7010dfdd178f3465135f42d28c9d435d60d0267f87b2581e1d7fafab606146fb70c620b1663b0d46e5d58ca1580913f76779e3c5ba65916db7cc73ccfb9a569e3165266c5ccf25240154aa60ff995327a2a8695a58d68b2105314ab370f84c8402211e00a029bf36156df8e525f809db876705baae274b69205fd5716448392648e0941c528402211e01a024897fb02565f515fa9fbb541eae07a132473349842b34786a06ec2a0d6ea64e801d548b699a7cee908420aac8d540a2de752823af731ec288b2774069730edecf3d4900535cf7714138d359177c9064e446a7730b9349b3d2ee0436b5072a855201a0000000000000000000000000000000000000000000000000000000000000000088000000000000000080120510ffbb84111ab51df90eb2f90211a0890231389e1c4e6a2f6e5b8154ea372063ed7d917cf0d32d7a2cd21adfd06842a00ef48a4e0bae1cbb1a3caa52a05cd1bedf1e22dc50e680b85838b4c4157f06fda036e5ab2773e21147d9baff1b131278acc2c6d94fe9b23d9fcfd03723db7bc345a062e246491852309e16167a9d3bf7496bea6cf7fc68bdde6bac349afe27a228bba09bb79be4b97ec382e2f13c4e552e85c5e8712e4ce079a84a19aa5008200d5b76a0e731649692d47833e6cf7053d746ea42d495ba405c363e9b7d0c672c8c4481b9a0e9bc22e8fa15d085a68c3bd14b9a750d310e1680ac5bdfa386f850aaa67905b8a0c352465d5662ac5b77de54c34855ab9c4e808378ab1d645cf7a30a8cb51caf26a00f4cb91d858bb51b8a795863d9552e1f105f2e3fb37f1d161c1dae4b203a3c72a02e7905a411dbd014e64713312927471c4b1c3885fda3ed5888c0fb192e6de359a05e60aa49704b32fcbcd9543275600ba900547b31ddf446d55c527f09f0f5c6f4a08886a98f2e030a70ec24f9b1096b548005b64c88faf516361a2a694abff08ac7a0f072b67b389d8c065c6585b92a89bcbdb4440ae210060f7b98ac92d7b1e62f8ca0e8ee249f924ccd80781c6892e42a15c60da9175802153a0ac71650b02c13ee36a0a8632cd2f0beeb0f89b728d65d9ea803bdf0b12a5e3d27cbe5832e4ceff8735ba0b10c2c47b02cd583395fc5e70520bf57b97ea460f5fbf600049db152afa0ab4880f90211a00971b494845868a4a6f5a36939740537be16ccc185b7724bb249439267aaacc3a0ff26bff9727522f6773d888a48e2f444b020e62fce9bf0c6e15eafa0d7c3cb58a006aa21a0b04e596b5a4ebbb384309a489e876c1be7e7a2b02a584b4530d66925a03af99e922ded079114bf3a92f2a21d0a5dd131d15e0f3e01c6410974fbc3d8cca011114fc621c9378780c8ded766139c9c1c5f03a8de0747eb17bf337ea4a2ca2da0604f4775514cb56b34732652f20b49abd5c40ba4310353e3e0271a7194379e9fa00266443ed0582ea87a478be34336830356a001e40dc4a05d139348d794bc0ba0a0c8e7006ec197ab21c2409125cdcff2e78f29fea018eca902733c017f43ca794da0dcf51b76b1845f2b5bce3e5e2ecac30166b619ff1f18329ecfc49d1f3de50d06a037c89a9609e09d5b06e33b8abd35e3f9073bc6bced657355ff26a44a1fb0a361a08290bc67998f67791a82885a0cb0e81cac9f35e02388febf3952b7b5b79f8885a00f172f431296d1e299667720093d4d3ccd4ec7aeec24241ccdea49ea1688646ba021de7fd2dc90ac8bb698c0888ec4ff9c19f5e5748d46b49dd7238da60e7fc3c6a018c43df08c3e25d13db0b22ee521f3f450aca517916b5cd5219c86b49e49a044a00b8131712251baad84b82f2a44b8a4868ac8d87f03fb631130fce4be948ed9c1a068aaddcd50b8e792c89aecebcc859ec916ed530162583515aa71815f8542b4e180f90211a0c14274d28a2e70b696f18013ed25d6dbad53e4f055cc95d9a831c025c2ed9b01a0632636410cd51a3c53b184462e1e407a0422ec61d24118ffbf9aad2e0158d97aa016c98b9e76bb41d55d32c15e53ff870dce6db42be5e31d669c10f60b70409912a01400aa2f7e63dfa22e66c1096a7032502c24b261a52074dcdbaf7672d411c163a086ce70144b17c65c8a205f3dfd182959f0b1fd7f90143ad50e6999752832694ba0f8d20b759725fe897eb1f8987aff3e33e2bb00f32ebd4ccf2068a3fc89ca6080a044de2aff10255376ed36b22eff5590eb58d3ee54d0e4cc7eca4d22ee11bf7387a03b8d65e333aa13f8afa5982868e7f7890ba9e9d1e71f57b6d3a7ecee4482d028a07983b553b56cdc0305676f9622ff64df4ef45f1400af3a94ad08cdfa43c8a6f6a09bfea18d16df95e1dc70ce655d8bd283c900157317ac53c05931096c80967c93a0df5c3ffdaab83f24dc1c21b63a655880aaba83e13ba3037db17f53dab3ecd908a03e664ae0cd067a6ad7aaed8ba647c34e2cffde9104cf9d385f302c7fcd714f85a012e7260db92227621f4ed41a8e50582cfef95cbad9d1b22ff14b82d3c59d9241a0a42731a74edae14df8c52c748eefa4dc148b679ff88e26ece01a753247875154a0a9bf2ef8979a58da04857064c92f0ca860c12e1e1739a419faa1a7a179e6a575a0da31d47321bec6cec888e06e9182d2b579b470e53fdb241f1d7c78f88c65133f80f90211a07cd4b1279b228ef40481922604a05d005cf3e596efbb7eecc920460725ffc958a04d0eb9ce763d8b0bd7d77eb2c450b1d1a68fa9d4a39f74fca416ae8b021dc252a0c8d17bafc04d0578123e28fe318c024cd8ffc2919906c9a0827f1e790c63ca36a03ec45bc4463a145cf8c75f30f706e244a745a1b27283c92dd8e29bc787fabeeba041e3e5a0474e922690d384c4ab603cf6cae1c5333510c5489a0b9cebdf9eb16da0872a5c56d4ddcfab1473aa4b5187aec0cd9ad6be7316293ed93e330649e6948aa033e7f70da3e2514734dfd9f6e22139c326c409ef5a098342d0ca117baae919a4a09822c694761ebd9436d546b74cb8a3c333887e3794521ac7ea5fa7f130306265a08f93244365f1bbd3d34190af7531cf9eb3bc752f4a7b37e2454811675098be24a0329fd3766ca5e0ead8ad587c20aac5d344426a175907f80b2ed4f3eda8001873a0704b7adbf076be42c914ebb93045d9dba99269d719e72f716e5c82e1c4d30ed6a05827484fc8250b11323578d86af3b2d98db47949bd7fc670fe62ac6d8b2b29dca0c50f5090c95cf05867a259e409440a47bb221fc0ca50765ab452a3b448fa68dfa0ea739dbb4d387dfb6f0aa8f13a8eeae6aef55b21512cb046f5cf6bf142a61d79a02fd141d9061f06e999c896bbc7b1d4d652be24a710c4893e9d7fe7aa30f7cfeea0135be94cdf13c38d956f6e782ac6ace9b8cc40305249ac24dee470a8236e7e1280f90211a08d19750aa033c3351c90890a8f3ce2bde5f8be2b419c6f45115d5e6fa822ee47a0af80bd31da73dd38aa307ddaf4a3a4967139569111706d42284c59fd65e962c8a0feadc5dfc37b565bf229e9c73931d9f2274a762ccd3fad295ec327c6afef9525a0974634e6d38bbff1b17032a6566dbb3ff4d964ddf8fd9461cc13be120a4c79eea08d665f3fffbb6db4768102cb4c238b7082ea97f148ebe52a4a7e2aba26c7c537a0d9f11599f8cd8e41ea2799bc67598f702cf749be0a8990f096f8047fba2839b0a09be08e8044dc3057d056efbf1418467b516c8eb78b6d3c04aa69a7da735886a7a0f098ba0d8d2aa43642190af04c3fa97ecd8a2fdbeb5d6a2fa8eb1312176c763aa0a5aee8d8da8b6c01810834dee37121817b4a6889237bc060c1b78dae010ccb6da0495ff86cf6a6a9d9b043c204db77369e9e9d9767d6af4d963c05468983d12a2ba0a8e2263e1242397424b80e4e5303d95c34484426f63348c4346bc7d7878a8cbda02d6d70eda441d1c2383000a093400ade51ac7a04abc1aa99a7ce7b1624cb731ba0d6e684d598642afd2d7934c57123128ba3485dd00862b738e8f18355286f7423a0e09050c854d7a0d5bfcdd14f07043fed81662126e2701a4566c1d7a261900c71a03ac1f69f8e20a8792ea98d671e979a20b51ed4b37b40e2671dc05dc4d6653ce7a0598310e43fc8ee41ddd015d5d2764c7cd4959840260cfa7cef41dff52ac51db980f90211a0f87b60a82c2c32d5439e3199ad0c3a009a7f5474a027dac454b09effadd1fbefa016bb48376076116f468f16394fc6898356d00b458ed14b901461d1afafc89e65a03d50a67e8ec93696c35865d9f03814e95406c8d04e5decc320b9a24e5beee1baa042fe91ec49a406bb4a35b05a7fc518b915550848ba48afdea839969737e94d19a0fb5a2ac85aa55665e6a21b4d77a80693cfa450ad3db8e22963f12740f79e948ba0a32564adebb5029e48a91c8f6a90d04de2d3042b4a44f20e347bd68a26ab0cdda026c57b9b5218aee794dc9b3f90935ff1374ede5b73847c902ca61a1c41105e9aa02b22a7bb0d1b84b9d89fbfc571f0c4122bb12add28e944b047e40323fbbc33bda08a831384faa68f9caa047a6200464e11cfe5f9f700a5ed9435e5241d9d2a501ca08987636c0999e2eb3d052f145cd6b23f50946f6d737da20b5a7e2e1a8dc91c97a0e4fc7281b24a4a9d96dd4af6804d6276bc1c176d8e34979da2e7140310e66adaa06cf03705b25b817df44e3bc2122f8f49ca8aa80f32e7cfc5ed69f6c37ff49c2ea0dc66c764a34bf9f1c62917dbfcd1b930fd9b9c4379d520104519ab3e80f05265a004c43c3abc9e1ee7c131611fb29bf3e55705b91f687b5b30bdb6c5fccb431232a0dc32b4bb85eb8facf38af40cd4f77d9159f4723c939ac466e106a6d3c7535847a060dfd3aff904b5bb6d5f2e37695e05c9b935fab7888bc88486f6e811f606e20080f9015180a0c2cb770a3d18eb1214a782cc81b79a7fd772716c2d050ef66011095c3774e8f7a08fc7d7da06fba7ffa69b095aae41147e3a55b89644682057cedab705ba7aefd5a05975b434f69398107a4d1729f8f56e75247df09c65b1a750797818607bf118df80a026cea4c13260b2a1dd74bb6fcc7cc36162d2856ce691a36165c633ba68f7b783a0f7b0c667509a4ce937c487b45bc53c0700543daf4f8c127fbe475b4e1084d2328080a0454eca3fcc32afd4c4000ccbb47732bbce342b1a9d374fb5872162f2c873625fa0b3e6c44579a731cc730a5472e83c6098fa2943e5b2c72f4475f0afea76848a87a03b8c951788b8c93366aedbf88f6c1ca6085cd0249025ce542f19294b40bb92f180a06efa682f711f1d9e189193bd4248884cecfa463028d015e6086a7de0a0889b0780a049ba777ae33a75e8c0c7bd07597d6e6fb43624537a579b9a06b20c89d6918b2980e482000ea07b2632b8b97e159d88f112a8dd9d44df2f3c4502e0c79a29297ea7f61f41f311f851a030590b16841225b9590cdc95b19176201d442ca0b931c6e4314d20a1c772ea9ba052e8f9f247cd159c65b304863d444087f6a60d7dbec3a0e4fa09f007b5a1c64f808080808080808080808080808080f86c9c20120c458c4c09a9448628f84e81161b308d5c4041a3d3a1ea329d0eb84df84b0487400e8b4f1c9c00a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47022440bac492386862ad3df4b666bc096b0505bb694dab0bec348681af766751cb839576e9c515a09c8bffa30a46296ccc56612490eb480d03bf948e10005bbcc0421f90b3d4e2244295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e9122442d4c407bbe49438ed859fe965b140dcf1aab71a993c1f7f6929d1fe2a17b4e14614ef9fc5bdc713d6631d675403fbeefac55611bf612700b1b65f4744861b80b0f7d6ab022443f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a224461dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d252244685b1ded8013785d6623cc18d214320b6bb647598a60f82a7bcf74b4cb053b9bfe83d0ed02a84ebb10865dfdd8e26e7535c43a1cccd268e860f502216b379dfc9971d358224472b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a5122447ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e22448b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d7886948522449bb832254baf4e8b4cc26bd2b52b31389b56e98bab764a39ff81dad720d5691b852898041a3842e09ecbac8025812d51b32223d8420e6ae51a01582220a10f7722de67c12244a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b7412244b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de72244b4dd66d7c2c7e57f628210187192fb89d4b99dd40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002244be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cd2244cc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a4192244ce2fd7544e0b2cc94692d4a704debef7bcb61328b64abe25614c9cfd32e456b4d521f29c8357f4af4606978296c9be93494072ac05fa86e3d27cc8d66e65000f8ba33fbb2244d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce7392244e2d3a739effcd3a99387d015e260eefac72ebea1956c470ddff48cb49300200b5f83497f3a3ccb3aeb83c5edd9818569038e61d197184f4aa6939ea5e9911e3e98ac6d212244ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c1921832244ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5b2244ef0274e31810c9df02f98fafde0f841f4e66a1cd98cbf822e4bc29f1701ac0350a3d042cd0756e9f74822c6481773ceb000641c51b870a996fe0f6a844510b1061f38cd02a44295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e912a442d4c407bbe49438ed859fe965b140dcf1aab71a993c1f7f6929d1fe2a17b4e14614ef9fc5bdc713d6631d675403fbeefac55611bf612700b1b65f4744861b80b0f7d6ab02a443f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a2a4461dd481a114a2e761c554b641742c973867899d38a80967d39e406a0a9642d41e9007a27fc1150a267d143a9f786cd2b5eecbdcc4036273705225b956d5e2f8f5eb95d252a44685b1ded8013785d6623cc18d214320b6bb647598a60f82a7bcf74b4cb053b9bfe83d0ed02a84ebb10865dfdd8e26e7535c43a1cccd268e860f502216b379dfc9971d3582a4470f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba72a4472b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a512a447ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e2a448b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d788694852a449bb832254baf4e8b4cc26bd2b52b31389b56e98bab764a39ff81dad720d5691b852898041a3842e09ecbac8025812d51b32223d8420e6ae51a01582220a10f7722de67c12a449f8ccdafcc39f3c7d6ebf637c9151673cbc36b888819ec5ec3e97e1f03bbb4bb6055c7a5feac8f4f259df58349a32bb5cb377e2cb1f362b77f1dd398cfd3e9dba46138c32a44a6f79b60359f141df90a0c745125b131caaffd12b772e180fbf38a051c97dabc8aaa0126a233a9e828cdafcc7422c4bb1f4030a56ba364c54103f26bad91508b5220b7412a44b218c5d6af1f979ac42bc68d98a5a0d796c6ab01b659ad0fbd9f515893fdd740b29ba0772dbde9b4635921dd91bd2963a0fc855e31f6338f45b211c4e9dedb7f2eb09de72a44b4dd66d7c2c7e57f628210187192fb89d4b99dd40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a44be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cd2a44cc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a4192a44d1d6bf74282782b0b3eb1413c901d6ecf02e8e28939e8fb41b682372335be8070199ad3e8621d1743bcac4cc9d8f0f6e10f41e56461385c8eb5daac804fe3f2bca6ce7392a44e2d3a739effcd3a99387d015e260eefac72ebea1956c470ddff48cb49300200b5f83497f3a3ccb3aeb83c5edd9818569038e61d197184f4aa6939ea5e9911e3e98ac6d212a44ee01c3b1283aa067c58eab4709f85e99d46de5fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a44ee226379db83cffc681495730c11fdde79ba4c0cae7bc6faa3f0cc3e6093b633fd7ee4f86970926958d0b7ec80437f936acf212b78f0cd095f4565fff144fd458d233a5b2a44ef0274e31810c9df02f98fafde0f841f4e66a1cd98cbf822e4bc29f1701ac0350a3d042cd0756e9f74822c6481773ceb000641c51b870a996fe0f6a844510b1061f38cd0").to_vec(); + let height = 35724800; + let trusted_height = 35724799; let trusted_current_validator_hash = - hex!("dc895253030c1833d95cfaa05c9aac223222099bc4b86ab99eeab6021ba64a71"); // empty validator set + hex!("97e642190471429a60b6964c475919444b7c9f8972a33507c30bd8d2c728745e"); let trusted_previous_validator_hash = - hex!("607d7394b225d4fdd5daa65ca82df3c2e01149269f77d11d55aad656f0095b09"); + hex!("1097f9094a26384a86fda6f22e5da7be996beab06fdb8eb865f5fd2b90b6f39e"); let new_current_validator_hash = - hex!("abe3670d5b312d3dd78123a31673e12413573eac5cada972eefb608edae91cac"); // empty validator set + hex!("732ae226da9beae0b00a2eec692956f0760b237f30f7b7e8ead93d92de794621"); let new_previous_validator_hash = - hex!("dc895253030c1833d95cfaa05c9aac223222099bc4b86ab99eeab6021ba64a71"); + hex!("97e642190471429a60b6964c475919444b7c9f8972a33507c30bd8d2c728745e"); do_test_success_update_client( header, height, diff --git a/light-client/src/client_state.rs b/light-client/src/client_state.rs index aeed1aa..4000b6b 100644 --- a/light-client/src/client_state.rs +++ b/light-client/src/client_state.rs @@ -312,7 +312,11 @@ mod test { revision_height: h.number - 1, }), account_proof: vec![], - current_validators: vec![], + current_validators: if h.is_epoch() { + h.get_validator_set().unwrap().validators + } else { + vec![] + }, previous_validators: validators_in_31297000(), }; let now = new_timestamp(h.timestamp + 1).unwrap(); @@ -340,7 +344,7 @@ mod test { revision_height: h.number - 1, }), account_proof: vec![1], - current_validators: vec![], + current_validators: header_31297200().get_validator_bytes().unwrap(), previous_validators: validators_in_31297000(), }; let valid_header: Header = raw.try_into().unwrap(); @@ -366,7 +370,11 @@ mod test { headers: h.iter().map(|e| e.try_into().unwrap()).collect(), trusted_height: Some(trusted_height), account_proof: vec![], - current_validators: vec![h[0].coinbase.clone()], + current_validators: if h[0].is_epoch() { + h[0].get_validator_set().unwrap().validators + } else { + vec![h[0].coinbase.clone()] + }, previous_validators: vec![h[0].coinbase.clone()], }; raw.try_into().unwrap() diff --git a/light-client/src/errors.rs b/light-client/src/errors.rs index d3c3847..db1d934 100644 --- a/light-client/src/errors.rs +++ b/light-client/src/errors.rs @@ -79,6 +79,7 @@ pub enum Error { MissingValidatorToVerifyVote(BlockNumber), UnexpectedNextCheckpointHeader(BlockNumber, BlockNumber), UnexpectedNextNextCheckpointHeader(BlockNumber, BlockNumber), + MissingTrustedCurrentValidators(BlockNumber), // Vote attestation UnexpectedTooManyHeadersToFinalize(BlockNumber, usize), @@ -308,6 +309,9 @@ impl core::fmt::Display for Error { Error::UnexpectedNextNextCheckpointHeader(e1, e2) => { write!(f, "UnexpectedNextNextCheckpointHeader : {} {}", e1, e2) } + Error::MissingTrustedCurrentValidators(e1) => { + write!(f, "MissingTrustedCurrentValidators : {}", e1) + } } } } diff --git a/light-client/src/header/eth_headers.rs b/light-client/src/header/eth_headers.rs index e00b5fc..8dab3de 100644 --- a/light-client/src/header/eth_headers.rs +++ b/light-client/src/header/eth_headers.rs @@ -20,6 +20,46 @@ pub struct ETHHeaders { } impl ETHHeaders { + pub fn verify_non_neighboring_epoch( + &self, + chain_id: &ChainId, + checkpoint: u64, + trusted_validators: TrustedValidatorSet, + next_validators: UntrustedValidatorSet, + ) -> Result<(), Error> { + let n_val = next_validators.try_borrow(&trusted_validators)?; + + // Ensure all the headers are successfully chained. + self.verify_cascading_fields()?; + + // Ensure valid seals + let hs: Vec = self + .all + .iter() + .filter(|h| h.number >= checkpoint) + .cloned() + .collect(); + for h in hs.iter() { + h.verify_seal(n_val, chain_id)?; + } + + let hs = ETHHeaders { + target: self.target.clone(), + all: hs, + }; + + // Ensure target is finalized + let (child, grand_child) = hs.verify_finalized()?; + + // Ensure BLS signature is collect + // At the just checkpoint BLS signature uses previous validator set. + for h in &[child, grand_child] { + let vote = h.get_vote_attestation()?; + vote.verify(h.number, n_val)?; + } + Ok(()) + } + pub fn verify( &self, chain_id: &ChainId, @@ -39,12 +79,7 @@ impl ETHHeaders { )?; // Ensure all the headers are successfully chained. - for (i, header) in self.all.iter().enumerate() { - if i < self.all.len() - 1 { - let child = &self.all[i + 1]; - child.verify_cascading_fields(header)?; - } - } + self.verify_cascading_fields()?; // Ensure valid seals let p_val = previous_validators.validators(); @@ -76,6 +111,16 @@ impl ETHHeaders { Ok(()) } + fn verify_cascading_fields(&self) -> Result<(), Error> { + for (i, header) in self.all.iter().enumerate() { + if i < self.all.len() - 1 { + let child = &self.all[i + 1]; + child.verify_cascading_fields(header)?; + } + } + Ok(()) + } + fn verify_finalized(&self) -> Result<(ÐHeader, ÐHeader), Error> { if self.all.len() < 3 { return Err(Error::InvalidVerifyingHeaderLength( @@ -561,6 +606,142 @@ mod test { f(headers, &c_val, &p_val, n_val_header, false); } + #[test] + fn test_success_verify_non_neighboring_epoch() { + let headers: ETHHeaders = vec![ + header_31297200(), + header_31297201(), + header_31297202(), + header_31297203(), + header_31297204(), + header_31297205(), + header_31297206(), + header_31297207(), + header_31297208(), + header_31297209(), + header_31297210(), + header_31297211(), + header_31297212(), + header_31297213(), + ] + .into(); + + let checkpoint = + headers.target.number + ValidatorSet::from(validators_in_31297000()).checkpoint(); + let n_val_raw = header_31297200().get_validator_bytes().unwrap().into(); + let n_val = UntrustedValidatorSet::new(&n_val_raw); + let t_val_raw = validators_in_31297000().into(); + let t_val = TrustedValidatorSet::new(&t_val_raw); + headers + .verify_non_neighboring_epoch(&mainnet(), checkpoint, t_val, n_val) + .unwrap(); + } + + #[test] + fn test_error_verify_non_neighboring_epoch() { + let headers: ETHHeaders = vec![header_31297200()].into(); + + // Insufficient trustedValidators + let checkpoint = + headers.target.number + ValidatorSet::from(validators_in_31297000()).checkpoint(); + let n_val_raw = header_31297200().get_validator_bytes().unwrap().into(); + let n_val = UntrustedValidatorSet::new(&n_val_raw); + let t_val_raw = vec![vec![0], vec![1], vec![2]].into(); + let t_val = TrustedValidatorSet::new(&t_val_raw); + let err = headers + .verify_non_neighboring_epoch(&mainnet(), checkpoint, t_val, n_val) + .unwrap_err(); + match err { + Error::InsufficientTrustedValidatorsInUntrustedValidators(_, found, required) => { + assert_eq!(found, 0); + assert_eq!(required, 1); + } + err => unreachable!("unexpected error type {:?}", err), + } + + // illegal sequence + let headers: ETHHeaders = vec![header_31297200(), header_31297202()].into(); + let n_val_raw = header_31297200().get_validator_bytes().unwrap().into(); + let n_val = UntrustedValidatorSet::new(&n_val_raw); + let t_val_raw = validators_in_31297000().into(); + let t_val = TrustedValidatorSet::new(&t_val_raw); + let err = headers + .verify_non_neighboring_epoch(&mainnet(), checkpoint, t_val, n_val) + .unwrap_err(); + match err { + Error::UnexpectedHeaderRelation(h1, h2, _, _, _, _) => { + assert_eq!(h1, 31297200); + assert_eq!(h2, 31297202); + } + err => unreachable!("unexpected error type {:?}", err), + } + + // illegal sealer after checkpoint + let mut headers: ETHHeaders = vec![ + header_31297200(), + header_31297201(), + header_31297202(), + header_31297203(), + header_31297204(), + header_31297205(), + header_31297206(), + header_31297207(), + header_31297208(), + header_31297209(), + header_31297210(), + header_31297211(), + header_31297212(), + header_31297213(), + ] + .into(); + headers.all.last_mut().unwrap().coinbase = vec![]; + let n_val_raw = header_31297200().get_validator_bytes().unwrap().into(); + let n_val = UntrustedValidatorSet::new(&n_val_raw); + let t_val_raw = validators_in_31297000().into(); + let t_val = TrustedValidatorSet::new(&t_val_raw); + let err = headers + .verify_non_neighboring_epoch(&mainnet(), checkpoint, t_val, n_val) + .unwrap_err(); + match err { + Error::UnexpectedCoinbase(h1) => { + assert_eq!(h1, 31297213); + } + err => unreachable!("unexpected error type {:?}", err), + } + + // invalid header size + let headers: ETHHeaders = vec![ + header_31297200(), + header_31297201(), + header_31297202(), + header_31297203(), + header_31297204(), + header_31297205(), + header_31297206(), + header_31297207(), + header_31297208(), + header_31297209(), + header_31297210(), + header_31297211(), + header_31297212(), + ] + .into(); + let n_val_raw = header_31297200().get_validator_bytes().unwrap().into(); + let n_val = UntrustedValidatorSet::new(&n_val_raw); + let t_val_raw = validators_in_31297000().into(); + let t_val = TrustedValidatorSet::new(&t_val_raw); + let err = headers + .verify_non_neighboring_epoch(&mainnet(), checkpoint, t_val, n_val) + .unwrap_err(); + match err { + Error::InvalidVerifyingHeaderLength(h1, size) => { + assert_eq!(h1, 31297200); + assert_eq!(size, 2); + } + err => unreachable!("unexpected error type {:?}", err), + } + } + fn create_before_checkpoint_headers() -> ETHHeaders { vec![header_31297208(), header_31297209(), header_31297210()].into() } diff --git a/light-client/src/header/mod.rs b/light-client/src/header/mod.rs index 0126643..d12113d 100644 --- a/light-client/src/header/mod.rs +++ b/light-client/src/header/mod.rs @@ -8,6 +8,7 @@ use parlia_ibc_proto::ibc::lightclients::parlia::v1::Header as RawHeader; use crate::commitment::decode_eip1184_rlp_proof; use crate::consensus_state::ConsensusState; +use crate::header::eth_header::ETHHeader; use crate::header::eth_headers::ETHHeaders; use crate::header::validator_set::{ @@ -78,26 +79,79 @@ impl Header { chain_id: &ChainId, consensus_state: &ConsensusState, ) -> Result<(), Error> { - let (c_val, p_val) = verify_validator_set( - consensus_state, - self.headers.target.is_epoch(), - self.height(), - self.trusted_height, - &self.previous_validators, - &self.current_validators, - )?; - self.headers.verify(chain_id, &c_val, &p_val) + if self.is_non_neighboring_epoch() { + let n_val = self.headers.target.get_validator_set()?; + let (t_val, n_val) = verify_validator_set_non_neighboring_epoch( + consensus_state, + self.height(), + self.trusted_height(), + &self.current_validators, + &n_val, + )?; + + // target height is epoch + let checkpoint = + self.height().revision_height() + self.previous_validators.checkpoint(); + self.headers + .verify_non_neighboring_epoch(chain_id, checkpoint, t_val, n_val) + } else { + let (c_val, p_val) = verify_validator_set( + consensus_state, + &self.headers.target, + self.height(), + self.trusted_height, + &self.previous_validators, + &self.current_validators, + )?; + self.headers.verify(chain_id, &c_val, &p_val) + } + } + + fn is_non_neighboring_epoch(&self) -> bool { + if !self.headers.target.is_epoch() { + return false; + } + let trusted_epoch = self.trusted_height.revision_height() / BLOCKS_PER_EPOCH; + let target_epoch = self.height().revision_height() / BLOCKS_PER_EPOCH; + trusted_epoch + 1 < target_epoch } } +fn verify_validator_set_non_neighboring_epoch<'a>( + consensus_state: &ConsensusState, + height: Height, + trusted_height: Height, + current_validators: &'a ValidatorSet, + next_validators: &'a ValidatorSet, +) -> Result<(TrustedValidatorSet<'a>, UntrustedValidatorSet<'a>), Error> { + if current_validators.validators.is_empty() { + return Err(Error::MissingTrustedCurrentValidators( + height.revision_height(), + )); + } + if consensus_state.current_validators_hash != current_validators.hash { + return Err(Error::UnexpectedCurrentValidatorsHash( + trusted_height, + height, + current_validators.hash, + consensus_state.previous_validators_hash, + )); + } + Ok(( + TrustedValidatorSet::new(current_validators), + UntrustedValidatorSet::new(next_validators), + )) +} + fn verify_validator_set<'a>( consensus_state: &ConsensusState, - is_epoch: bool, + target: ÐHeader, height: Height, trusted_height: Height, previous_validators: &'a ValidatorSet, current_validators: &'a ValidatorSet, ) -> Result<(EitherValidatorSet<'a>, TrustedValidatorSet<'a>), Error> { + let is_epoch = target.is_epoch(); let header_epoch = height.revision_height() / BLOCKS_PER_EPOCH; let trusted_epoch = trusted_height.revision_height() / BLOCKS_PER_EPOCH; @@ -118,6 +172,16 @@ fn verify_validator_set<'a>( )); } + let val_in_extra = target.get_validator_set()?; + if val_in_extra.hash != current_validators.hash { + return Err(Error::UnexpectedCurrentValidatorsHash( + trusted_height, + height, + val_in_extra.hash, + current_validators.hash, + )); + } + Ok(( EitherValidatorSet::Untrusted(UntrustedValidatorSet::new(current_validators)), TrustedValidatorSet::new(previous_validators), @@ -184,15 +248,10 @@ impl TryFrom for Header { } // Epoch header contains validator set - let current_validators = if headers.target.is_epoch() { - headers - .target - .get_validator_bytes() - .ok_or_else(|| Error::MissingValidatorInEpochBlock(headers.target.number))? - } else { - value.current_validators - }; - if current_validators.is_empty() { + // - not a epoch block: current epoch validators (which must be in trusted cons state) + // - non neighboring epoch header: validators in trusted cons state + // - neighboring epoch header: validators in extra data + if value.current_validators.is_empty() { return Err(Error::MissingCurrentTrustedValidators( headers.target.number, )); @@ -203,7 +262,7 @@ impl TryFrom for Header { headers, trusted_height, previous_validators: value.previous_validators.into(), - current_validators: current_validators.into(), + current_validators: value.current_validators.into(), }) } } @@ -235,10 +294,12 @@ pub(crate) mod testdata; pub(crate) mod test { use crate::consensus_state::ConsensusState; use crate::errors::Error; + use crate::header::constant::BLOCKS_PER_EPOCH; + use crate::header::eth_headers::ETHHeaders; - use crate::header::testdata::{header_31297200, header_31297201}; + use crate::header::testdata::{header_31297200, header_31297201, validators_in_31297000}; use crate::header::validator_set::{EitherValidatorSet, ValidatorSet}; - use crate::header::{verify_validator_set, Header}; + use crate::header::{verify_validator_set, verify_validator_set_non_neighboring_epoch, Header}; use crate::misc::{new_height, Hash, Validators}; use light_client::types::Time; use parlia_ibc_proto::ibc::core::client::v1::Height; @@ -348,8 +409,8 @@ pub(crate) mod test { headers: vec![h.try_into().unwrap()], trusted_height: Some(trusted_height.clone()), account_proof: vec![], - current_validators: vec![], - previous_validators: vec![h.coinbase.clone()], + current_validators: header_31297200().get_validator_bytes().unwrap(), + previous_validators: validators_in_31297000(), }; let result = Header::try_from(raw.clone()).unwrap(); assert_eq!(result.headers.target, *h); @@ -367,7 +428,7 @@ pub(crate) mod test { ); assert_eq!( &result.current_validators.validators, - &h.get_validator_bytes().unwrap() + &raw.current_validators ); } @@ -427,15 +488,14 @@ pub(crate) mod test { previous_validators_hash: [2u8; 32], }; + // epoch let height = new_height(0, 400); let trusted_height = new_height(0, 201); - - // Same validator set as previous - let current_validators = &mut to_validator_set([3u8; 32]); - let previous_validators = &mut to_validator_set(cs.current_validators_hash); + let current_validators = &header_31297200().get_validator_set().unwrap(); + let previous_validators = &to_validator_set(cs.current_validators_hash); let (c_val, p_val) = verify_validator_set( &cs, - true, + &header_31297200(), height, trusted_height, previous_validators, @@ -444,38 +504,25 @@ pub(crate) mod test { .unwrap(); match c_val { EitherValidatorSet::Untrusted(r) => { - let validators = r.try_borrow(&p_val).unwrap(); - assert_eq!(*validators, current_validators.validators); - } - _ => unreachable!("unexpected trusted"), - } - - let current_validators = &mut to_validator_set([3u8; 32]); - let previous_validators = - &mut to_validator_set_with_validators(cs.current_validators_hash, vec![vec![2]]); - let (c_val, p_val) = verify_validator_set( - &cs, - true, - height, - trusted_height, - previous_validators, - current_validators, - ) - .unwrap(); - match c_val { - EitherValidatorSet::Untrusted(r) => { - assert!(r.try_borrow(&p_val).is_err()); + assert!(r.try_borrow(&p_val).is_err()) } _ => unreachable!("unexpected trusted"), } + // not epoch + let cs = ConsensusState { + state_root: [0u8; 32], + timestamp: Time::now(), + current_validators_hash: [1u8; 32], + previous_validators_hash: [2u8; 32], + }; let height = new_height(0, 599); let trusted_height = new_height(0, 400); - let current_validators = &mut to_validator_set(cs.current_validators_hash); - let previous_validators = &mut to_validator_set(cs.previous_validators_hash); + let current_validators = &to_validator_set(cs.current_validators_hash); + let previous_validators = &to_validator_set(cs.previous_validators_hash); let (c_val, _p_val) = verify_validator_set( &cs, - false, + &header_31297201(), height, trusted_height, previous_validators, @@ -501,11 +548,11 @@ pub(crate) mod test { let height = new_height(0, 400); let trusted_height = new_height(0, 199); - let current_validators = &mut to_validator_set([1u8; 32]); - let previous_validators = &mut to_validator_set([2u8; 32]); + let current_validators = &to_validator_set([1u8; 32]); + let previous_validators = &to_validator_set([2u8; 32]); let err = verify_validator_set( &cs, - true, + &header_31297200(), height, trusted_height, previous_validators, @@ -521,10 +568,10 @@ pub(crate) mod test { } let trusted_height = new_height(0, 200); - let previous_validators = &mut to_validator_set([3u8; 32]); + let previous_validators = &to_validator_set([3u8; 32]); let err = verify_validator_set( &cs, - true, + &header_31297200(), height, trusted_height, previous_validators, @@ -545,7 +592,7 @@ pub(crate) mod test { let trusted_height = new_height(0, 200); let err = verify_validator_set( &cs, - false, + &header_31297201(), height, trusted_height, previous_validators, @@ -561,11 +608,11 @@ pub(crate) mod test { } let trusted_height = new_height(0, 400); - let current_validators = &mut to_validator_set([1u8; 32]); - let previous_validators = &mut to_validator_set([3u8; 32]); + let current_validators = &to_validator_set([1u8; 32]); + let previous_validators = &to_validator_set([3u8; 32]); let err = verify_validator_set( &cs, - false, + &header_31297201(), height, trusted_height, previous_validators, @@ -583,11 +630,11 @@ pub(crate) mod test { } let trusted_height = new_height(0, 400); - let current_validators = &mut to_validator_set([3u8; 32]); - let previous_validators = &mut to_validator_set([2u8; 32]); + let current_validators = &to_validator_set([3u8; 32]); + let previous_validators = &to_validator_set([2u8; 32]); let err = verify_validator_set( &cs, - false, + &header_31297201(), height, trusted_height, previous_validators, @@ -603,5 +650,145 @@ pub(crate) mod test { } _ => unreachable!("err {:?}", err), } + + let cs = ConsensusState { + state_root: [0u8; 32], + timestamp: Time::now(), + current_validators_hash: [4u8; 32], + previous_validators_hash: [2u8; 32], + }; + let height = new_height(0, 400); + let trusted_height = new_height(0, 399); + let current_validators = &to_validator_set([1u8; 32]); + let previous_validators = &to_validator_set([4u8; 32]); + let err = verify_validator_set( + &cs, + &header_31297200(), + height, + trusted_height, + previous_validators, + current_validators, + ) + .unwrap_err(); + match err { + Error::UnexpectedCurrentValidatorsHash(t, h, header_hash, request_hash) => { + assert_eq!(t, trusted_height); + assert_eq!(h, height); + assert_eq!( + header_hash, + header_31297200().get_validator_set().unwrap().hash + ); + assert_eq!(request_hash, current_validators.hash); + } + _ => unreachable!("err {:?}", err), + } + } + + #[test] + fn test_success_verify_validator_set_non_neighboring_epoch() { + let cs = ConsensusState { + state_root: [0u8; 32], + timestamp: Time::now(), + current_validators_hash: [1u8; 32], + previous_validators_hash: [2u8; 32], + }; + + let height = new_height(0, 600); + let trusted_height = new_height(0, 201); + + let trusted_validators = &to_validator_set(cs.current_validators_hash); + let next_validators = &to_validator_set([4u8; 32]); + let (_c_val, _n_val) = verify_validator_set_non_neighboring_epoch( + &cs, + height, + trusted_height, + trusted_validators, + next_validators, + ) + .unwrap(); + } + + #[test] + fn test_error_verify_validator_set_non_neighboring_epoch() { + let cs = ConsensusState { + state_root: [0u8; 32], + timestamp: Time::now(), + current_validators_hash: [1u8; 32], + previous_validators_hash: [2u8; 32], + }; + + let height = new_height(0, 600); + let trusted_height = new_height(0, 201); + + // empty trusted validator + let mut trusted_validators = to_validator_set(cs.current_validators_hash); + trusted_validators.validators = Validators::new(); + let next_validators = &to_validator_set([4u8; 32]); + let err = verify_validator_set_non_neighboring_epoch( + &cs, + height, + trusted_height, + &trusted_validators, + next_validators, + ) + .unwrap_err(); + match err { + Error::MissingTrustedCurrentValidators(t) => { + assert_eq!(t, height.revision_height()); + } + _ => unreachable!("err {:?}", err), + } + + // untrusted validator + let trusted_validators = &to_validator_set([5u8; 32]); + let err = verify_validator_set_non_neighboring_epoch( + &cs, + height, + trusted_height, + trusted_validators, + next_validators, + ) + .unwrap_err(); + match err { + Error::UnexpectedCurrentValidatorsHash(t, h, hash, cons_hash) => { + assert_eq!(t, trusted_height); + assert_eq!(h, height); + assert_eq!(hash, trusted_validators.hash); + assert_eq!(cons_hash, cons_hash); + } + _ => unreachable!("err {:?}", err), + } + } + + #[test] + fn test_is_non_neighboring_epoch() { + let mut h = Header { + account_proof: vec![], + headers: ETHHeaders { + target: header_31297201(), + all: vec![], + }, + trusted_height: new_height(0, 0), + previous_validators: vec![].into(), + current_validators: vec![].into(), + }; + + // not epoch + let base = 31297200; + h.trusted_height = new_height(0, base); + assert!(!h.is_non_neighboring_epoch()); + h.trusted_height = new_height(0, base - BLOCKS_PER_EPOCH); + assert!(!h.is_non_neighboring_epoch()); + h.trusted_height = new_height(0, base - BLOCKS_PER_EPOCH - 1); + assert!(!h.is_non_neighboring_epoch()); + + // epoch + h.headers.target.number = 31297200; + h.trusted_height = new_height(0, base); + assert!(!h.is_non_neighboring_epoch()); + h.trusted_height = new_height(0, base - BLOCKS_PER_EPOCH); + assert!(!h.is_non_neighboring_epoch()); + h.trusted_height = new_height(0, base - BLOCKS_PER_EPOCH - 1); + assert!(h.is_non_neighboring_epoch()); } } diff --git a/proto/src/prost/google.protobuf.rs b/proto/src/prost/google.protobuf.rs index f453d67..518a909 100644 --- a/proto/src/prost/google.protobuf.rs +++ b/proto/src/prost/google.protobuf.rs @@ -44,14 +44,9 @@ pub struct FileDescriptorProto { #[prost(message, optional, tag = "9")] pub source_code_info: ::core::option::Option, /// The syntax of the proto file. - /// The supported values are "proto2", "proto3", and "editions". - /// - /// If `edition` is present, this value must be "editions". + /// The supported values are "proto2" and "proto3". #[prost(string, optional, tag = "12")] pub syntax: ::core::option::Option<::prost::alloc::string::String>, - /// The edition of the proto file, which is an opaque string. - #[prost(string, optional, tag = "13")] - pub edition: ::core::option::Option<::prost::alloc::string::String>, } /// Describes a message type. #[allow(clippy::derive_partial_eq_without_eq)] @@ -114,90 +109,6 @@ pub struct ExtensionRangeOptions { /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, - /// For external users: DO NOT USE. We are in the process of open sourcing - /// extension declaration and executing internal cleanups before it can be - /// used externally. - #[prost(message, repeated, tag = "2")] - pub declaration: ::prost::alloc::vec::Vec, - /// Any features defined in the specific edition. - #[prost(message, optional, tag = "50")] - pub features: ::core::option::Option, - /// The verification state of the range. - /// TODO(b/278783756): flip the default to DECLARATION once all empty ranges - /// are marked as UNVERIFIED. - #[prost( - enumeration = "extension_range_options::VerificationState", - optional, - tag = "3", - default = "Unverified" - )] - pub verification: ::core::option::Option, -} -/// Nested message and enum types in `ExtensionRangeOptions`. -pub mod extension_range_options { - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct Declaration { - /// The extension number declared within the extension range. - #[prost(int32, optional, tag = "1")] - pub number: ::core::option::Option, - /// The fully-qualified name of the extension field. There must be a leading - /// dot in front of the full name. - #[prost(string, optional, tag = "2")] - pub full_name: ::core::option::Option<::prost::alloc::string::String>, - /// The fully-qualified type name of the extension field. Unlike - /// Metadata.type, Declaration.type must have a leading dot for messages - /// and enums. - #[prost(string, optional, tag = "3")] - pub r#type: ::core::option::Option<::prost::alloc::string::String>, - /// If true, indicates that the number is reserved in the extension range, - /// and any extension field with the number will fail to compile. Set this - /// when a declared extension field is deleted. - #[prost(bool, optional, tag = "5")] - pub reserved: ::core::option::Option, - /// If true, indicates that the extension must be defined as repeated. - /// Otherwise the extension must be defined as optional. - #[prost(bool, optional, tag = "6")] - pub repeated: ::core::option::Option, - } - /// The verification state of the extension range. - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] - #[repr(i32)] - pub enum VerificationState { - /// All the extensions of the range must be declared. - Declaration = 0, - Unverified = 1, - } - impl VerificationState { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - VerificationState::Declaration => "DECLARATION", - VerificationState::Unverified => "UNVERIFIED", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "DECLARATION" => Some(Self::Declaration), - "UNVERIFIED" => Some(Self::Unverified), - _ => None, - } - } - } } /// Describes a field within a message. #[allow(clippy::derive_partial_eq_without_eq)] @@ -610,9 +521,6 @@ pub struct FileOptions { /// determining the ruby package. #[prost(string, optional, tag = "45")] pub ruby_package: ::core::option::Option<::prost::alloc::string::String>, - /// Any features defined in the specific edition. - #[prost(message, optional, tag = "50")] - pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. /// See the documentation for the "Options" section above. #[prost(message, repeated, tag = "999")] @@ -700,10 +608,6 @@ pub struct MessageOptions { /// this is a formalization for deprecating messages. #[prost(bool, optional, tag = "3", default = "false")] pub deprecated: ::core::option::Option, - /// NOTE: Do not set the option in .proto files. Always use the maps syntax - /// instead. The option should only be implicitly set by the proto compiler - /// parser. - /// /// Whether the message is an automatically generated map entry type for the /// maps field. /// @@ -721,24 +625,12 @@ pub struct MessageOptions { /// use a native map in the target language to hold the keys and values. /// The reflection APIs in such implementations still need to work as /// if the field is a repeated message field. + /// + /// NOTE: Do not set the option in .proto files. Always use the maps syntax + /// instead. The option should only be implicitly set by the proto compiler + /// parser. #[prost(bool, optional, tag = "7")] pub map_entry: ::core::option::Option, - /// Enable the legacy handling of JSON field name conflicts. This lowercases - /// and strips underscored from the fields before comparison in proto3 only. - /// The new behavior takes `json_name` into account and applies to proto2 as - /// well. - /// - /// This should only be used as a temporary measure against broken builds due - /// to the change in behavior for JSON field name conflicts. - /// - /// TODO(b/261750190) This is legacy behavior we plan to remove once downstream - /// teams have had time to migrate. - #[deprecated] - #[prost(bool, optional, tag = "11")] - pub deprecated_legacy_json_field_conflicts: ::core::option::Option, - /// Any features defined in the specific edition. - #[prost(message, optional, tag = "12")] - pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, @@ -748,10 +640,8 @@ pub struct MessageOptions { pub struct FieldOptions { /// The ctype option instructs the C++ code generator to use a different /// representation of the field than it normally would. See the specific - /// options below. This option is only implemented to support use of - /// \[ctype=CORD\] and \[ctype=STRING\] (the default) on non-repeated fields of - /// type "bytes" in the open source release -- sorry, we'll try to include - /// other types in a future version! + /// options below. This option is not yet implemented in the open source + /// release -- sorry, we'll try to include it in a future version! #[prost( enumeration = "field_options::CType", optional, @@ -801,6 +691,7 @@ pub struct FieldOptions { /// call from multiple threads concurrently, while non-const methods continue /// to require exclusive access. /// + /// /// Note that implementations may choose not to check required fields within /// a lazy sub-message. That is, calling IsInitialized() on the outer message /// may return true even if the inner message has missing required fields. @@ -812,8 +703,11 @@ pub struct FieldOptions { /// check its required fields, regardless of whether or not the message has /// been parsed. /// - /// As of May 2022, lazy verifies the contents of the byte stream during - /// parsing. An invalid byte stream will cause the overall parsing to fail. + /// As of 2021, lazy does no correctness checks on the byte stream during + /// parsing. This may lead to crashes if and when an invalid byte stream is + /// finally parsed upon access. + /// + /// TODO(b/211906113): Enable validation on lazy fields. #[prost(bool, optional, tag = "5", default = "false")] pub lazy: ::core::option::Option, /// unverified_lazy does no correctness checks on the byte stream. This should @@ -830,39 +724,12 @@ pub struct FieldOptions { /// For Google-internal migration only. Do not use. #[prost(bool, optional, tag = "10", default = "false")] pub weak: ::core::option::Option, - /// Indicate that the field value should not be printed out when using debug - /// formats, e.g. when the field contains sensitive credentials. - #[prost(bool, optional, tag = "16", default = "false")] - pub debug_redact: ::core::option::Option, - #[prost(enumeration = "field_options::OptionRetention", optional, tag = "17")] - pub retention: ::core::option::Option, - #[prost( - enumeration = "field_options::OptionTargetType", - repeated, - packed = "false", - tag = "19" - )] - pub targets: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "20")] - pub edition_defaults: ::prost::alloc::vec::Vec, - /// Any features defined in the specific edition. - #[prost(message, optional, tag = "21")] - pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, } /// Nested message and enum types in `FieldOptions`. pub mod field_options { - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, PartialEq, ::prost::Message)] - pub struct EditionDefault { - #[prost(string, optional, tag = "1")] - pub edition: ::core::option::Option<::prost::alloc::string::String>, - /// Textproto value. - #[prost(string, optional, tag = "2")] - pub value: ::core::option::Option<::prost::alloc::string::String>, - } #[derive( Clone, Copy, @@ -878,12 +745,6 @@ pub mod field_options { pub enum CType { /// Default mode. String = 0, - /// The option \[ctype=CORD\] may be applied to a non-repeated field of type - /// "bytes". It indicates that in C++, the data should be stored in a Cord - /// instead of a string. For very large strings, this may reduce memory - /// fragmentation. It may also allow better performance when parsing from a - /// Cord, or when parsing with aliasing enabled, as the parsed Cord may then - /// alias the original buffer. Cord = 1, StringPiece = 2, } @@ -951,121 +812,10 @@ pub mod field_options { } } } - /// If set to RETENTION_SOURCE, the option will be omitted from the binary. - /// Note: as of January 2023, support for this is in progress and does not yet - /// have an effect (b/264593489). - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] - #[repr(i32)] - pub enum OptionRetention { - RetentionUnknown = 0, - RetentionRuntime = 1, - RetentionSource = 2, - } - impl OptionRetention { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - OptionRetention::RetentionUnknown => "RETENTION_UNKNOWN", - OptionRetention::RetentionRuntime => "RETENTION_RUNTIME", - OptionRetention::RetentionSource => "RETENTION_SOURCE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "RETENTION_UNKNOWN" => Some(Self::RetentionUnknown), - "RETENTION_RUNTIME" => Some(Self::RetentionRuntime), - "RETENTION_SOURCE" => Some(Self::RetentionSource), - _ => None, - } - } - } - /// This indicates the types of entities that the field may apply to when used - /// as an option. If it is unset, then the field may be freely used as an - /// option on any kind of entity. Note: as of January 2023, support for this is - /// in progress and does not yet have an effect (b/264593489). - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] - #[repr(i32)] - pub enum OptionTargetType { - TargetTypeUnknown = 0, - TargetTypeFile = 1, - TargetTypeExtensionRange = 2, - TargetTypeMessage = 3, - TargetTypeField = 4, - TargetTypeOneof = 5, - TargetTypeEnum = 6, - TargetTypeEnumEntry = 7, - TargetTypeService = 8, - TargetTypeMethod = 9, - } - impl OptionTargetType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - OptionTargetType::TargetTypeUnknown => "TARGET_TYPE_UNKNOWN", - OptionTargetType::TargetTypeFile => "TARGET_TYPE_FILE", - OptionTargetType::TargetTypeExtensionRange => { - "TARGET_TYPE_EXTENSION_RANGE" - } - OptionTargetType::TargetTypeMessage => "TARGET_TYPE_MESSAGE", - OptionTargetType::TargetTypeField => "TARGET_TYPE_FIELD", - OptionTargetType::TargetTypeOneof => "TARGET_TYPE_ONEOF", - OptionTargetType::TargetTypeEnum => "TARGET_TYPE_ENUM", - OptionTargetType::TargetTypeEnumEntry => "TARGET_TYPE_ENUM_ENTRY", - OptionTargetType::TargetTypeService => "TARGET_TYPE_SERVICE", - OptionTargetType::TargetTypeMethod => "TARGET_TYPE_METHOD", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "TARGET_TYPE_UNKNOWN" => Some(Self::TargetTypeUnknown), - "TARGET_TYPE_FILE" => Some(Self::TargetTypeFile), - "TARGET_TYPE_EXTENSION_RANGE" => Some(Self::TargetTypeExtensionRange), - "TARGET_TYPE_MESSAGE" => Some(Self::TargetTypeMessage), - "TARGET_TYPE_FIELD" => Some(Self::TargetTypeField), - "TARGET_TYPE_ONEOF" => Some(Self::TargetTypeOneof), - "TARGET_TYPE_ENUM" => Some(Self::TargetTypeEnum), - "TARGET_TYPE_ENUM_ENTRY" => Some(Self::TargetTypeEnumEntry), - "TARGET_TYPE_SERVICE" => Some(Self::TargetTypeService), - "TARGET_TYPE_METHOD" => Some(Self::TargetTypeMethod), - _ => None, - } - } - } } #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct OneofOptions { - /// Any features defined in the specific edition. - #[prost(message, optional, tag = "1")] - pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, @@ -1083,18 +833,6 @@ pub struct EnumOptions { /// is a formalization for deprecating enums. #[prost(bool, optional, tag = "3", default = "false")] pub deprecated: ::core::option::Option, - /// Enable the legacy handling of JSON field name conflicts. This lowercases - /// and strips underscored from the fields before comparison in proto3 only. - /// The new behavior takes `json_name` into account and applies to proto2 as - /// well. - /// TODO(b/261750190) Remove this legacy behavior once downstream teams have - /// had time to migrate. - #[deprecated] - #[prost(bool, optional, tag = "6")] - pub deprecated_legacy_json_field_conflicts: ::core::option::Option, - /// Any features defined in the specific edition. - #[prost(message, optional, tag = "7")] - pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, @@ -1108,14 +846,6 @@ pub struct EnumValueOptions { /// this is a formalization for deprecating enum values. #[prost(bool, optional, tag = "1", default = "false")] pub deprecated: ::core::option::Option, - /// Any features defined in the specific edition. - #[prost(message, optional, tag = "2")] - pub features: ::core::option::Option, - /// Indicate that fields annotated with this enum value should not be printed - /// out when using debug formats, e.g. when the field contains sensitive - /// credentials. - #[prost(bool, optional, tag = "3", default = "false")] - pub debug_redact: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, @@ -1123,9 +853,6 @@ pub struct EnumValueOptions { #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct ServiceOptions { - /// Any features defined in the specific edition. - #[prost(message, optional, tag = "34")] - pub features: ::core::option::Option, /// Is this service deprecated? /// Depending on the target platform, this can emit Deprecated annotations /// for the service, or it will be completely ignored; in the very least, @@ -1152,9 +879,6 @@ pub struct MethodOptions { default = "IdempotencyUnknown" )] pub idempotency_level: ::core::option::Option, - /// Any features defined in the specific edition. - #[prost(message, optional, tag = "35")] - pub features: ::core::option::Option, /// The parser stores options it doesn't recognize here. See above. #[prost(message, repeated, tag = "999")] pub uninterpreted_option: ::prost::alloc::vec::Vec, @@ -1248,273 +972,6 @@ pub mod uninterpreted_option { pub is_extension: bool, } } -/// TODO(b/274655146) Enums in C++ gencode (and potentially other languages) are -/// not well scoped. This means that each of the feature enums below can clash -/// with each other. The short names we've chosen maximize call-site -/// readability, but leave us very open to this scenario. A future feature will -/// be designed and implemented to handle this, hopefully before we ever hit a -/// conflict here. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct FeatureSet { - #[prost(enumeration = "feature_set::FieldPresence", optional, tag = "1")] - pub field_presence: ::core::option::Option, - #[prost(enumeration = "feature_set::EnumType", optional, tag = "2")] - pub enum_type: ::core::option::Option, - #[prost(enumeration = "feature_set::RepeatedFieldEncoding", optional, tag = "3")] - pub repeated_field_encoding: ::core::option::Option, - #[prost(enumeration = "feature_set::StringFieldValidation", optional, tag = "4")] - pub string_field_validation: ::core::option::Option, - #[prost(enumeration = "feature_set::MessageEncoding", optional, tag = "5")] - pub message_encoding: ::core::option::Option, - #[prost(enumeration = "feature_set::JsonFormat", optional, tag = "6")] - pub json_format: ::core::option::Option, - #[prost(message, optional, boxed, tag = "999")] - pub raw_features: ::core::option::Option<::prost::alloc::boxed::Box>, -} -/// Nested message and enum types in `FeatureSet`. -pub mod feature_set { - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] - #[repr(i32)] - pub enum FieldPresence { - Unknown = 0, - Explicit = 1, - Implicit = 2, - LegacyRequired = 3, - } - impl FieldPresence { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - FieldPresence::Unknown => "FIELD_PRESENCE_UNKNOWN", - FieldPresence::Explicit => "EXPLICIT", - FieldPresence::Implicit => "IMPLICIT", - FieldPresence::LegacyRequired => "LEGACY_REQUIRED", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "FIELD_PRESENCE_UNKNOWN" => Some(Self::Unknown), - "EXPLICIT" => Some(Self::Explicit), - "IMPLICIT" => Some(Self::Implicit), - "LEGACY_REQUIRED" => Some(Self::LegacyRequired), - _ => None, - } - } - } - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] - #[repr(i32)] - pub enum EnumType { - Unknown = 0, - Open = 1, - Closed = 2, - } - impl EnumType { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - EnumType::Unknown => "ENUM_TYPE_UNKNOWN", - EnumType::Open => "OPEN", - EnumType::Closed => "CLOSED", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "ENUM_TYPE_UNKNOWN" => Some(Self::Unknown), - "OPEN" => Some(Self::Open), - "CLOSED" => Some(Self::Closed), - _ => None, - } - } - } - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] - #[repr(i32)] - pub enum RepeatedFieldEncoding { - Unknown = 0, - Packed = 1, - Expanded = 2, - } - impl RepeatedFieldEncoding { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - RepeatedFieldEncoding::Unknown => "REPEATED_FIELD_ENCODING_UNKNOWN", - RepeatedFieldEncoding::Packed => "PACKED", - RepeatedFieldEncoding::Expanded => "EXPANDED", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "REPEATED_FIELD_ENCODING_UNKNOWN" => Some(Self::Unknown), - "PACKED" => Some(Self::Packed), - "EXPANDED" => Some(Self::Expanded), - _ => None, - } - } - } - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] - #[repr(i32)] - pub enum StringFieldValidation { - Unknown = 0, - Mandatory = 1, - Hint = 2, - None = 3, - } - impl StringFieldValidation { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - StringFieldValidation::Unknown => "STRING_FIELD_VALIDATION_UNKNOWN", - StringFieldValidation::Mandatory => "MANDATORY", - StringFieldValidation::Hint => "HINT", - StringFieldValidation::None => "NONE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "STRING_FIELD_VALIDATION_UNKNOWN" => Some(Self::Unknown), - "MANDATORY" => Some(Self::Mandatory), - "HINT" => Some(Self::Hint), - "NONE" => Some(Self::None), - _ => None, - } - } - } - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] - #[repr(i32)] - pub enum MessageEncoding { - Unknown = 0, - LengthPrefixed = 1, - Delimited = 2, - } - impl MessageEncoding { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - MessageEncoding::Unknown => "MESSAGE_ENCODING_UNKNOWN", - MessageEncoding::LengthPrefixed => "LENGTH_PREFIXED", - MessageEncoding::Delimited => "DELIMITED", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "MESSAGE_ENCODING_UNKNOWN" => Some(Self::Unknown), - "LENGTH_PREFIXED" => Some(Self::LengthPrefixed), - "DELIMITED" => Some(Self::Delimited), - _ => None, - } - } - } - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] - #[repr(i32)] - pub enum JsonFormat { - Unknown = 0, - Allow = 1, - LegacyBestEffort = 2, - } - impl JsonFormat { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - JsonFormat::Unknown => "JSON_FORMAT_UNKNOWN", - JsonFormat::Allow => "ALLOW", - JsonFormat::LegacyBestEffort => "LEGACY_BEST_EFFORT", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "JSON_FORMAT_UNKNOWN" => Some(Self::Unknown), - "ALLOW" => Some(Self::Allow), - "LEGACY_BEST_EFFORT" => Some(Self::LegacyBestEffort), - _ => None, - } - } - } -} /// Encapsulates information about the original source file from which a /// FileDescriptorProto was generated. #[allow(clippy::derive_partial_eq_without_eq)] @@ -1688,59 +1145,10 @@ pub mod generated_code_info { #[prost(int32, optional, tag = "3")] pub begin: ::core::option::Option, /// Identifies the ending offset in bytes in the generated code that - /// relates to the identified object. The end offset should be one past + /// relates to the identified offset. The end offset should be one past /// the last relevant byte (so the length of the text = end - begin). #[prost(int32, optional, tag = "4")] pub end: ::core::option::Option, - #[prost(enumeration = "annotation::Semantic", optional, tag = "5")] - pub semantic: ::core::option::Option, - } - /// Nested message and enum types in `Annotation`. - pub mod annotation { - /// Represents the identified object's effect on the element in the original - /// .proto file. - #[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration - )] - #[repr(i32)] - pub enum Semantic { - /// There is no effect or the effect is indescribable. - None = 0, - /// The element is set or otherwise mutated. - Set = 1, - /// An alias to the element is returned. - Alias = 2, - } - impl Semantic { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Semantic::None => "NONE", - Semantic::Set => "SET", - Semantic::Alias => "ALIAS", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "NONE" => Some(Self::None), - "SET" => Some(Self::Set), - "ALIAS" => Some(Self::Alias), - _ => None, - } - } - } } } /// `Any` contains an arbitrary serialized protocol buffer message along with a @@ -1911,6 +1319,7 @@ pub struct Any { /// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) /// .setNanos((int) ((millis % 1000) * 1000000)).build(); /// +/// /// Example 5: Compute Timestamp from Java `Instant.now()`. /// /// Instant now = Instant.now(); @@ -1919,6 +1328,7 @@ pub struct Any { /// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) /// .setNanos(now.getNano()).build(); /// +/// /// Example 6: Compute Timestamp from current time in Python. /// /// timestamp = Timestamp() @@ -1948,9 +1358,10 @@ pub struct Any { /// \[`strftime`\]() with /// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use /// the Joda Time's \[`ISODateTimeFormat.dateTime()`\]( -/// ) +/// /// ) to obtain a formatter capable of generating timestamps in this format. /// +/// #[derive(::serde::Serialize, ::serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] @@ -2026,6 +1437,7 @@ pub struct Timestamp { /// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 /// microsecond should be expressed in JSON format as "3.000001s". /// +/// #[derive(::serde::Serialize, ::serde::Deserialize)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)]