diff --git a/bootstrap_builder.py b/bootstrap_builder.py new file mode 100644 index 00000000..3007e222 --- /dev/null +++ b/bootstrap_builder.py @@ -0,0 +1,173 @@ +import asyncio +from typing import List + +from jamcodec.base import JamBytes + +from pyjamaz.hashing import blake2b_256_hash +from pyjamaz.models.builder import Instruction, ServiceRegistry +from pyjamaz.models.common import Authorizer, RefinementContext, WorkPackage, WorkItem, WorkItemExtrinsic, Preimage +from pyjamaz.transport.rpc.ws_client import WebsocketClient + + +# Bootstrap service - Helper functions + +async def get_service_registry(client) -> ServiceRegistry: + best_block = await client.finalizedBlock() + block_hash = best_block["header_hash"] + services_registry = await client.serviceValue(block_hash, 0, b'\x10service_registry') + + return ServiceRegistry.from_jam_bytes(JamBytes(services_registry)) + + +async def create_empty_workpackage(client: WebsocketClient) -> WorkPackage: + best_block = await client.finalizedBlock() + block_hash = best_block["header_hash"] + block_timeslot = best_block["slot"] + + state_root = await client.stateRoot(block_hash) + beefy_root = await client.beefyRoot(block_hash) + + authorizer = Authorizer( + code_hash=bytes.fromhex('1f5b06efb68e00d58f668d6c2f5e34bdfe52c18d1176b2304e0bae45f367ca6f'), + params=b'' + ) + + context = RefinementContext( + anchor=block_hash, + state_root=state_root, + beefy_root=beefy_root, + lookup_anchor=block_hash, + lookup_anchor_slot=block_timeslot, + prerequisites=[] + ) + + work_package = WorkPackage( + authorization=b'', + auth_code_host=0, + authorizer=authorizer, + context=context, + items=[] + ) + + return work_package + +async def create_bootservice_workpackage(client: WebsocketClient, instruction: Instruction, extrinsic: List[bytes]) -> WorkPackage: + work_package = await create_empty_workpackage(client) + work_package.items.append( + WorkItem( + accumulate_gas_limit=10000000, + code_hash=bytes.fromhex('bc804dccb6bae35cd48cc1e11e426e7ba218727e2ba7dd43e8163f4f5d06333f'), + export_count=0, + extrinsic=[WorkItemExtrinsic.from_blob(e) for e in extrinsic], + import_segments=[], + payload=instruction.to_jam_bytes().to_bytes(), + refine_gas_limit=5000000000, + service=0 + ) + ) + + return work_package + +# Bootstrap service - Script + +async def main(): + + async with WebsocketClient("ws://127.0.0.1:19800") as client: + # Init vars + bootstrap_service_id = 0 + registration = "test123" + # TODO update incompatible 0.6.5 preimage + new_service_preimage = bytes.fromhex("27000c746573742d7365727669636505302e312e300a4170616368652d322e3001066e6f626f6479280f0000000001000020002f55736572732f61726a616e2f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f6a616d2d636f6465632d302e312e302f7372632f636f6465632e72732f55736572732f61726a616e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032342d31312d30312d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7261775f7665632e72734f75744f66426f756e6473496e646578556e6b6e6f776e53746f7261676546756c6c426164436f72654e6f436173684761734c696d6974546f6f4c6f77416374696f6e496e76616c69645468697320697320526566696e6520696e207468652054657374205365727669636520682077697468207061796c6f6164206c656e2048656c6c6f205468697320697320416363756d756c61746520696e20746865205465737420536572766963652068207769746820206974656d736c61737462616c616e6365206c6f777372632f6c69622e72730000000000000b000000000000000c000000000000000b00000000000000070000000000000006000000000000000e000000000000000d00000000000000effefffffafeffff06ffffff11ffffff18ffffff1effffff2cffffff4f75744f66426f756e6473496e646578556e6b6e6f776e53746f7261676546756c6c426164436f72654e6f436173684761734c696d6974546f6f4c6f77416374696f6e496e76616c69642f55736572732f61726a616e2f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f6a616d2d636f6465632d302e312e302f7372632f636f6d706163742e72735472616e73666572206174202066726f6d206820746f2068206f6620206d656d6f206c617374747862616c616e6365206c6f777372632f6c69622e727300000000000b000000000000000c000000000000000b00000000000000070000000000000006000000000000000e000000000000000d00000000000000dcfeffffe7fefffff3fefffffefeffff05ffffff0bffffff19ffffff63616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c75652f55736572732f61726a616e2f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f6a616d2d70766d2d636f6d6d6f6e2d302e312e32322f7372632f6d656d2e72734572726f722f55736572732f61726a616e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032342d31312d30312d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f736c6963652e72734c61796f75744572726f7263616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c75652f55736572732f61726a616e2f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f6a616d2d70766d2d636f6d6d6f6e2d302e312e32322f7372632f6d656d2e7273756e6b6e6f776e206572726f7220636f64653a202f55736572732f61726a616e2f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f6a616d2d70766d2d636f6d6d6f6e2d302e312e32322f7372632f726573756c742e72732230782e2e2e2e2e2e00010000000000000000000000000000006361706163697479206f766572666c6f772f55736572732f61726a616e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032342d31312d30312d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7261775f7665632e72732f55736572732f61726a616e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032342d31312d30312d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f616c6c6f632e72736d656d6f727920616c6c6f636174696f6e206f6620206279746573206661696c65642f55736572732f61726a616e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032342d31312d30312d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f737472696e672e72734572726f722f55736572732f61726a616e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032342d31312d30312d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f737472696e672e72736120666f726d617474696e6720747261697420696d706c656d656e746174696f6e2072657475726e656420616e206572726f72207768656e2074686520756e6465726c79696e672073747265616d20646964206e6f742f55736572732f61726a616e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032342d31312d30312d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f666d742e72732f55736572732f61726a616e2f2e7275737475702f746f6f6c636861696e732f6e696768746c792d323032342d31312d30312d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f666d742f6e756d2e72733078303030313032303330343035303630373038303931303131313231333134313531363137313831393230323132323233323432353236323732383239333033313332333333343335333633373338333934303431343234333434343534363437343834393530353135323533353435353536353735383539363036313632363336343635363636373638363937303731373237333734373537363737373837393830383138323833383438353836383738383839393039313932393339343935393639373938393963616c6c656420604f7074696f6e3a3a756e77726170282960206f6e206120604e6f6e65602076616c75650101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020202020202020202020202020202020202020202020202020202020202030303030303030303030303030303030404040404000000000000000000000072616e676520737461727420696e64657820206f7574206f662072616e676520666f7220736c696365206f66206c656e677468203a20000000000100000000005e00000000000000920400001e00000000000100000000005e000000000000006c0400000f00000000000100000000005e000000000000009e040000100000005e0001000000000079000000000000002b0200001100000021010100000000002300000000000000440101000000000013000000000000005d010100000000002700000000000000840101000000000007000000000000008b0101000000000006000000000000000000000000000000010000000000000001000000000000004200000000000000a0010100000000000a000000000000001a000000340000004e0201000000000060000000000000002d0100003d000000ae020100000000000c00000000000000ba020100000000000600000000000000c0020100000000000500000000000000c5020100000000000500000000000000ca020100000000000600000000000000000000000000000001000000000000000100000000000000a200000000000000e1020100000000000a000000000000002800000040000000000000000000000000000000000000000100000000000000ce000000000000006f0301000000000062000000000000002a00000009000000d6030100000000007700000000000000060300001a000000000000000000000000000000000000000100000000000000d600000000000000830401000000000062000000000000001700000059000000e5040100000000001400000000000000f904010000000000650000000000000021000000120000005e0501000000000001000000000000005e0501000000000001000000000000005f0501000000000002000000000000006105010000000000030000000000000078050100000000001100000000000000890501000000000079000000000000002b02000011000000790601000000000015000000000000008e060100000000000d0000000000000002060100000000007700000000000000b60100000d00000002060100000000007700000000000000b40100000d000000fc0000000000000018000000000000000800000000000000fe000000000000000401000000000000f6000000000000009b0601000000000078000000000000008d0500001b0000000c010000000000001800000000000000080000000000000018010000000000001e01000000000000f60000000000000018070100000000007800000000000000ea010000170000000000000000000000000000000000000001000000000000000e01000000000000e60701000000000075000000000000007e0200000e000000180701000000000078000000000000008d0500001b0000005b0801000000000078000000000000005b00000017000000c80a0100000000001200000000000000da0a010000000000220000000000000001000000000000000000000000000000fc0a01000000000002000000000000001b3f000080ae02b6decf000e0162017f019c01b601c501da01ec010802210251038203c103d503ff032b055805a006bf06e706fb0612072a076f07820754086908e8088a092c0ad70a120b380b770ba80bbd0be10bf00b060c650ca30ce50c270d690d9e0dca0da20ed70ee60ebd0ffb0f39105f107510d4101b116711a511b311c111d11136123e12b3120a13a91306141c142a147b149614a81446157a15f3150b167c16081722177b17a117b817031877189418f81849196a19d3190f1a201a301a471a6c1a901aa81ab91ac91ae01a051b291b411b731bd21b061c221c2b1d7a1dfb1d0a1e221e391edf1e821fa01f26207320e0209321f7210d22f5225e238a239123a023cb23f723fe232a24cd24f824fd240c257e25c725f82536264f267a26a626ad26d9267c27a727e627fc274b28d6286429bc29cc290b2ab82a042b562b7b2bbd2bea2b002c2a2c462c9b2cab2dfd2d172e452eb92ec32ed930fb310932273328eb110000285713000028f9149511e0fd7b1018027b1510027b1608026496648549117095197849117808492180007b175106f3011407f8ffffffffffff7f7b17083307300b017b17187b1520281c821638846601821c2852060802821610c9c6069519785106ce0182178000821a7033086be6860cc97a087b1c28aec86cc8c705ac75260233079800d6750833075208230233089800ca8509821b08ac9b1502510a1782177896a898007b1788017b18980133070828053307017b17900195170801330808951a88015010025f07821708015207c501821710017b17787b1570821520821c28017b161033060164c7330801285782167896579800c8760695188800330980006467501004bd348217407b6780008217307b6788008217507a6790008217487a6794009555017b158000821c28821638d8c6088217589577ff956601821520510716ff7b18387b175848218801951888013309046457501006ef1e5207edfe811788017b175048218801951888013309046457501008d21e5207d0fe811788017b17484921880195188801330908645750100ab51e5207b3fe821788017b17409517880133098000330850100ccf349518880133098000645750100e8c1e52078afe951708019518880133098000501010f13349218801951888013309086457501012651e520763fe821788017b1730951788009518080133098000501014c333821580008217707b1638ab75e3fe951770821818501016ff0628d4fe829808829933077b18687b1960281d82988217708299087b1860140800000000000000807b1968aa872c821868821960821a7ba81064a87ba9082826821870510814330908140700000000000000808218280f140700000000000000808218017b8782101802821510028216080295112002320082171001821818013309180b01288b1f33073309180b0128811f3309180b0128791f951150ff7b10a8007b15a0007b16980064967b182049114095194849114801491150510658017b173307300b017b1718281082171001821608c9760651064d01821750821a4033080002e68605c97a087b1510ae5858c87505ac757d0198583b330752088c0197590557098501510a1582174897aa057b17787b1a880033070128053307017b178000951758330801951a78501018dd04821758520746018217607b17487b15408215100149219000492188004921800049117895187833092082172050101acf1c52078a007b160833069555ff7b152801821790008218880082198000821a78821550821b407b17707b18687b19607b1a58abb50e95174082181850101cd004821748975805c8870795185833092050101ef6319555017b1550821728aa670eff492190004921880049218000491178951878330920821720501020521c956601510790821710ae76e8fe8218405108179788053309018217140a000000000000008028588217140a0000000000000080284a8298088299330a7b18387b1930282e9517488278821a408279087b1830140800000000000000807b19388217ab8a0f140a0000000000000080280f8218388219307b78107b7908017b7a8210a8008215a000821698009511b000320033073309180b0128991d8217608218683309180b01288b1d3309180b0128831d9511887b10707b15687b16607b1810828808ae98101405000000000000008028dd005109ae007b173307330c330a01649b017b1b1833080040e68b06c97c08ae6821c86705ac75c7005705c3007b16086476510c137b1a487b1c58330701280ac87608282c3307017b1750951730330801951a48645950102203038217305207a200821a38645c64586467821608017b1c286485ac7882007b1a20c87a088217106469501024f91a52073a821b18c96b0b6457821c28821a20520b79ff6458140500000000000000808217ab5c0d282e3308330c330a01017b7a087b781064c5281c1405000000000000008082182851080a330901821728058217017b75821070821568821660951178320033073309180b01286d1c3309000b01645828682d8217388218403309180b0128551c951110fe7b10e8017b15e0017b16d80164967b1830491150951958491158084911605106ad017b17330bb8001407f8ffffffffffff7f7b1708140700000000000000807b17283307300b017b1720281482171801821610c97606330bb80051068001821760821250330859e68605c972087b1518ae5862c8570aac7ab101d6ba0833075208c00196a9b800821c08ac9cb5017b1a385102178217589628b8007b1720017b18300133070828053307017b172801951768330808951a20015010268e01821768520770018217707b17588217387b175001951768821830501028d108821768821828aa87787b161033058217189577ff7b173801951720019518683309b80050102ae42e821660821750ab760e95175082182050102cc7028217589668b800c88707951820013309b80050102eb92e9566017b1660821738aa5713ff9517688218305010306608821768955501821828ab87a4821718ae75f9fe821560510544821758957620140700000000000000807b1738280c9555ff9566b8005105258268e051080a330901501032048268f8821738aa78e35108e0330901501034da28d68218505108189688b8003309088217140a000000000000008028588217140a0000000000000080284a8298088299330a7b18487b1940282e9517588278821a508279087b1840140800000000000000807b19488217ab8a0f140a0000000000000080280f8218488219407b78107b7908017b7a8210e8018215e0018216d8019511f001320033073309180b0128201a8217708218783309180b0128121a3309180b01280a1a9511e07b10187b15107b160882ab08649c64856476510b1882a81051081782a7645964ca7b1c5010362d142815510c172805510c1264c764587b1c5010380014821c2805645701887801db77057b65087b6c107b6882101882151082160895112032009511b07b10487b15407b16386476827a95a701648b51076397a801e4780898893b3307520955330904e4980597590557095b7b1b510a1482670897aa057b17207b1a3033070128053307017b1728951708330801951a2050103a46ff82170852071e8217107b67087b65821048821540821638951150320064b9282a19821710821818821b64b9281d1964b92818199511b07b10487b15407b16386476827a95a701648c51077697a801e47807330804e4870533089800d68509330752095e965998003308f1140bf8ffffffffffff7fac9b5c7b1c510a1582670896a898007b17207b183033070828053307017b1728951708330808951a2050103ca4fe82170852071e8217107b67087b65821048821540821638951150320064c9288818821710821818821c64c9287b1864c92876189511b07b10487b15407b16386476827a95a701648c51077697a801e47807330804e487053308b800d68509330752095e9659b8003308f1140bf8ffffffffffff7fac9b5c7b1c510a1582670896a8b8007b17207b183033070828053307017b1728951708330808951a2050103e02fe82170852071e8217107b67087b65821048821540821638951150320064c928e617821710821818821c64c928d91764c928d417c88909ac89900064ac6473827a97a7013308330601330201330504da6205330608db8506e49608e47806330801d668093307520979966901140800000000000000801405ffffffffffffff7fac955f510a15643582370896a8017b17187b182864c7280764353307017b17206417951a1864c850104057fd82175207238217087b57087b56821040821538821630951148320033073309480b012837178217088218103309480b012829173309480b012821177c77977903330ab00101977702330be80101c8b7078177c8a9098299c87b0a648764a8287923510711140701000000000000807b57284c7c1708510755140601000000000000807817079517077b170849111001461127951708951827330901501046da145207197c17279578ff330905ae980d9566ff7b5678570828057b560182103882153082162895114032006467501048860d8377520791978820988920951708646850104af8f882170814080000000000000080aa8771ff8217188218108219087b57107b58087b5928b483775207347b1838646750104e3e0d8377520725978820988920951760016468501050aff88218600114070000000000000080ab7822140700000000000000807b57018210900182158801821680019511980132007b1830821768017b1728821770017b172049217801492170014921680149216001951860013309206467501052ec1352077601821778018218700182196801821a60017b17587b18507b19487b1a4049217801492170014921680149216001951860013309206467501054ae1352073801821778018218700182196801821a60017b17f8007b18f0007b19e8007b1ae000492178014921700149216801492160019518600133092064675010566c135207f600821778018218700182196801821a60017b1718017b1810017b1908017b1a0001492178014921700149216801492160019518600133092064675010582a135207b400821778018218700182196801821a60017b1738017b1830017b1928017b1a20014921780149217001492168014921600195186001330920646750105ae812520772821778018218700182196801821a60017b1758017b1850017b1948017b1a40014821600195186001330904646750105cb31252073d811760017b171895176001646833005e9511a87b10507b15487b16406486647564873300a40028620b8218600114070000000000000080ab7820140700000000000000807b5782183001510839fe330901821728282ffe7b18108217e0008218e8007b17c0008217f0007b18c8008218f800821900017b17d000821708017b18d8007b19a000821810017b17a80082171801821938017b18b000821830017b17b8007b199800821728017b18900082182001821940017b178800821748017b1880007b1960821850017b176882175801821968017b19087b1870821870017b187b177849217801492170014921680149216001951860013309206467501060af11510725821708140800000000000000807b58821830821910510931ff3309018218302827ff9557d80095186001330920501062f4269557b800951840330920501064e5268217c0008218c8008219d000821ad8007b57307b58387b59407b5a488217a0008218a8008219b000821ab8007b57507b58587b59607b5a68821780008218880082199000821a98007b57707b58787b5980007b5a8800821778821870821968821a607b57a8007b58a0007b5998007b5a90008217307b578217287b57088217207b57108217107b57188217087b572082177b57288217187a57b0008217387a57f800289cfc951128ff7b10d0007b15c8007b16c000648664754921b8004921b0004921a8004921a0009518a000330920646750106694105207c9008217b8008218b0008219a800821aa0007b17387b18307b19287b1a204921b8004921b0004921a8004921a0009518a0003309206467501068561052078b008217b8008218b0008219a800821aa0007b17587b18507b19487b1a404921b8004921b0004921a8004921a0009518a000330920646750106a181052074d8217b8008218b0008219a800821aa0007b17787b18707b19687b1a60646750106ccf0883775207259788209889209517a000646850106e40f48218a00014070000000000000080ab7822140700000000000000807b57018210d0008215c8008216c0009511d80032007b18188217a8007b17108217b0007b17084921b8004921b0004921a8004921a0009518a00033092064675010707d0f52074a8217b8008218b0008219a800821aa0007b1798007b1890007b1988007b1a800064673300729511e07b10187b15107b16086475460164183309013306013300aa0028340f51072014070000000000000080017b57821818510865ff330901821710285bff7b189517a00064683300749511c07b10387b15307b162864866475461108951808330901646733004428e80e8218a0001407000000000000008014090100000000000080aa98aa8217b0008218a8008219a0007b57287b58207b59189557309518203309205010762624955750951840330920501078182495577095186033092050107a0a24955790009518800033092050107cfa238217187b578217107b57088217087b571082177b57b00028abfe951180fe7b1078017b1570017b166801648564769777209877209788209888207b17407b184895176895184033007e951168fe7b1090017b1588017b16800164866475648733004c28f606835850208000f709821868140700000000000000807b1818aa78f6008217707b170882157881176001821880007b1810330828017a17249517247b17407b184895176033085a017b1750821788007b177b15607b18583307600b017b176849117002492188009518407b18784921800002951728951868502082006c12821630821b3833070233083309646a0a640182182851080333075701017b1768491170068216087b16787b158000951740951868330902330084009511b07b10487b15407b16387b173305958a207b1a08958a08284708821818510807330901018218105108073309010182154882184082165051080733090101645764688210780182157001821668019511800132003307440301330a880c01330ba80c0133082b951940280922951138ff7b10c0007b15b8007b16b000837a838995175864a8330086009511987b10607b15587b165064767b18109787209877207b19189798209888207b17207b18289517203300b6002883058117748218688219587b198219607b19087a173c7b18a80095173c330828017b17880033075a017b1890009518a8007b1898007b17a0003307800b017b175849116003491178951788007b176849117002951740951858502088001911821548821b5033070233083309645a33008a000a640182184051080b33090150208c00058217a800510796008218089585289677b800957848ff140700000000000000807b173033079101017b17107b18288256f0821730aa760f8257f87b172082577b1718018258d851080b33090150208e0005821730aa762a951758330904821810821a20821b185020900015088217585117024a51060b33090150209200058218285108199555b800958848ff7b18288256f0821730ab76a228ab821851080733090801330733088210c0008215b8008216b0009511c80032007c1760781788003307950101330ab00b01330bd00b0133080b951988002862209511d07b1028837a838995170864a8330094009511987b10607b15587b165064767b18109787209877207b19189798209888207b17207b18289517203300c20028e603811720811824821908821a10821b187a177a180496b79800c8a7077b1a087b19187b1a107b1720951708641895190450209600113307330882102895113032009511d0fd7b1028027b1520027b16180264758277188256087b19487b18407b1710aa769101330756017b1738330728017b173033075a017b17283307d8007b17203307000c017b17183307d002017b17087b15280b8215821710aa76580195175033099800646850209800d91f956698007b56089517e8009518503309980050209a00c11f8217407b17c8018217387b17d001951778017b17d8018218307b18e0018217487b17e8017b18f001951768017b17f8018217287b1700029517e8007b1708028217207b1710028217187b1798014921a001054921b8019518c8017b18a8014921b00105951780019518980150209c00a30e82158801821b900133070233083309645a0a6401821880015108038217407b17c8018217387b17d001951778017b17d8018218307b18e0018217487b17e8017b18f001951768017b17f8018217287b1700029517e8007b1708028217207b1710028217187b1798014921a001054921b8019518c8017b18a8014921b00105951780019518980150209e00170e82158801821b90019517c801330906821808645a5020a00089058217c80151170234821880015108adfe33090128a6fe82581051080d825796889800330908018210280282152002821618029511300232007c17d001781798013307d60201330a500c01330b700c0133080b9519980128ea1d7c77977903330af00201977702330b280301c8b7078177c8a9098299c87b0a648764a828101783775207960097882098892095172864685020a60008eb82182814070000000000000080aa78747b18208217388218305107497b15107b17189775059555e0140700000000000000807b177b180864870151056295762033092064685020a800ad1d83789555e064675708e8821510821682192052090d280e33068219205109073309010149111833080114070000000000000080ab7634140700000000000000807b5701821050821548821640951158320082162082151082180814070000000000000080aa76d27b567b58088217187b571028d1520788007c185108205228ff00214901641833090864575020ac00be07520767821833062864648628606c865706073309284284674033090151073a84672033090251073184671033090351072884670833090451071f84670433090551071684670233090651070d8467013309075207f61549016418645764955020ae005a075107173306010164678210188215108216089511203200646933068557079b77ff8218e07907975903cf9707c8780828d89511d87b10207b15187b161064754611089518083309013306015020b00009075207b6007c18085108a9005228ff002449110895180833090864575020b200e80652076c8218089887208e76288a006c885708073306284284874033060151073a84872033060251073184871033060351072884870833060451071f84870433060551071684870233060651070d84870133060752071f157b18491108951808645764695020b4007f0651070833060128268567079b77ff8218088219e07907976603cf6707c878089887208e7628089887208e76016467821020821518821610951128320083777b18085207739517205020b8000fff83777b185207639517205020ba00fffe83775207559788209889209517309518205020bc009deb82153014070000000000000080aa75338217408218387b67107b68088218185020be00c9017b658217087a671882177a671c82106082155882165095116832008218185020c000a5013307440301330a880c01330ba80c0133082b95194f28bd1a83777b18085207739517205020c40076fe83777b185207639517205020c60066fe83775207559788209889209517309518205020c80033e582153014070000000000000080aa75338217408218387b67107b68088218185020ca0030017b658217087a671882177a671c82106082155882165095116832008218185020cc000c013307440301330a880c01330ba80c0133082b95194f28241a33090564873308d1030128631382abc8b5059599ff95aa105209f55705b50051053c64863308017b181864575020d000f7005107a20064682827821730821828821920821a7ba7107ba8087ba982104882154082163895115032003307010133067b15207b17107b1728491130018217208285087b18188288c96707ac5729821710017b1710c8670764595020d200fa19c856068218189588107b1630821708ab78ce2897951720330a017b1810646864593300d4009511b87b10407b15387b1630285cee82181082163082172828b5491118013309c00c01821718645828110633090b648733084d04012882129511f07b100897872098772033080428041951070b82100895111032003307580401330ad80c01330bf80c0133082b9519072801193309659a9aa99588ffd29808c887076579c88a0793973200330b65bc9acb9599ffd2b909c8a90b65bbc89c0c93bc510c0f647be6a80964c764b828281964c732009511a07b10587b15507b164864756487649864a964ba0a03015617f60e3308017b587b570828233308ffaa871b9578093309077b17ae98218d87067857083307027b572805490501821058821550821648951160320033075a0164187b18387b17403307100d017b1708491110014911289518387b1818491120013308200d0195170828a7119511807b10787b15707b1668648564763307800033081f6469015107137d9a9599019577ffada8f5510af228293309800001c876087c8851080b957701ab97f52805647901641764685020da009511821751073e7b164911080864177b17583307e2007b17603307580d017b1728491130029517587b1738825720825828491140014911489519283300dc0028aa0a8217088218107b17187b18209517187b17583307de007b17603307380d017b1728491130024911489519588257208258287b1938491140019519285020dc006c0a8210788215708216689511800032008279827a08648b649764a864b9648a6478649764a928b60e8277951178ff7b1080007c776482330c951b8000287609951128ff7b10d0007b15c8007b16c000827608827955260304a1005106de018287207b17388287287b17303307e0007b1728140720000000080000007b172033076805017b1718017b19409517407b17788217287b1780004921880002492198004921a000024921a8008217207b17b0004621b800038217187b174849115001951888007b1868491170019518787b18584911600164959519488217388218305020e4008809520757019566ff9559015206982846017b16088287207b17287b18108287287b1720330500023307e0007b1738140720000000080000007b171833076805017b17307b196496017b16409517407b17788217387b1780004921880002492198004921a000024921a8008217187b17b0004621b800038217307b174849115001951888007b1868491170019518787b1858491160019519488217288218205020e600e5085207b4009555ff95660152059a33086405013309038217105020e800140f6478330701520895008217088218c88707957500fe33060002140720000000080000007b1728017b15409517407b17788217387b1780004921880002492198004921a000024921a8008217287b17b0004621b800038217307b174849115001951788007b176882181082872082882849117001951a787b1a58491160019519485020ea0041085207109566ff95550152069833072806330701018210d0008215c8008216c0009511d80032009511d87b10207b15187b16108276086495ac962782797b197b17086487649864595020ec005915c956078218c858088219087b987b970801d8560782102082151882161095112832009511b07b10487b15407b1638647682779579017b18510952977801e49808330908e498055705435107108268087b18207b1730330701017b1728951708330801951a2064595020ee00f1008217085207208217107b67087b6582104882154082163895115032003307821928300182171082181882192825019511b87b10407b15387b163001c88909ac89900064ac6473827a97a7013308330601330201330504da6205330608db8506e49608e47806330801d668093307520977966901140800000000000000801405ffffffffffffff7fac955d510a15643582370896a8017b17187b182864c7280764353307017b17206417951a1864c85020f0003d82175207228217087b57087b56821040821538821630951148320033073309880d01287b8217088218103309880d01286e3309880d0128679511e07b10187b15107b160882ab08649c64856476510b1982a81051081882a7645964ca7b1c5020f2008bfa2816510c182805510c1364c764587b1c5020f4005dfa821c2805645701887801db77057b65087b6c107b68821018821510821608951120320052072464979511d064783307780d017b1749110801491120491110084911186417287e0c6487019511b834080000037b1752086433075a0164187b18387b17403307a00d017b1708491110024911289517387b1718491120013309c00d019517089511b8827a28827b207b1a287b1b20827a18827b10827c0882777b1a187b1b107b1c087b1764177b17307b19384611404611410033075a0164187b18387b17403307a00d017b1708491110024911289517387b1718491120013308d80d0195170828dd0b9511e07b10187b15107b16086489828a08828818330b01aaba13520a13520810827c103306330501282b5108173308f00d01821018821510821608951120282e058298827c1082798286088285c9c909ac69317b17827808c8c80764586469646564c65020f8006e12c8560682177b761033078210188215108216089511203200330a01330b017b17821764c864695020fa008afd8217827c1028b9827851080b827708330901320032009511e07b10187b15107b16086475827c108277c9c7076496ac972b7b1c825708c8c70764695020000101128217c876067b561033078210188215108216089511203200330a01330b0164577b1864c86469502002011dfd8218825c1028bf9511d87b10207b15187b1610330980006475ae982b8256108257ab761564577b183308200e015020060171fc821801825708c867077878956601289b008b870b48110c52071595170d9889068699c00078190c33060228528b871052072295170e98890c8699e00078190c97893498993a9599800078190d330603282d95170f9889128699f00078190c97892e98993a9599800078190d97893498993a9599800078190e33060401825c10825a84883f86888000c9ca0a7878ac6a2f7b1c825708c8c70795180c646950200801ff108217c87606017b561033078210208215188216109511283200330a01330b01645764c8646950200a011cfc825c1028bf827851080b82770833090132003200330905648733081307012898099511a87b10507b15487b16406486828b08828a7b1718510b5b330595a70864b8018279c895059588ff9577105208f582671851071982a708887701885810d2870752073057052d975501015705dc005105297b1b087b1a103308017b18645750201001ecf65107c500821a10821b08280d33053307012806330701017b15208268187b1728491130511b0113520b1252080f33063305330801283b51082e3308380e01951720646950201201a0025107383307900701330a800e01330ba00e0133085695193f28830f82a60882a8ac653a330501c85707646950201401d40fc865057b153001821730821828821920821a187ba7107ba8087ba98210508215488216409511583200951720330a01330b0164853308646950201601defa645882153082172828af4901013309680e018217645828e4fb9511e07b10187b15107b16086475827c108277c9c7076496ac972b7b1c825708c8c707646950201a01520f8217c876067b561033078210188215108216089511203200330a01330b0164577b1864c8646950201c016efa8218825c1028bf9511d87b10207b15187b1610330980006475ae982b8256108257ab761564577b183308b80e0150202001c2f9821801825708c867077878956601289b008b870b48110c52071595170d9889068699c00078190c33060228528b871052072295170e98890c8699e00078190c97893498993a9599800078190d330603282d95170f9889128699f00078190c97892e98993a9599800078190d97893498993a9599800078190e33060401825c10825a84883f86888000c9ca0a7878ac6a2f7b1c825708c8c70795180c646950202201500e8217c87606017b561033078210208215188216109511283200330a01330b01645764c86469502024016df9825c1028bf84780f88890a868a30958857db9a0878b8ff95bbff98770495cc015207e59ac7800056278000223309d30801330801330a026427502026014502821080009511880032003309d00e0133088000283c0b951178ff7b10800081776482330c951b80000184780f88890a868a30958857db9a0878b8ff95bbff8b780495cc0164875208e39ac7800056278000223309d30801330801330a02642750202a01e001821080009511880032003309d00e013308800028d70a9511807b10787b15707b166849115820330a03781a608296204911284911387b17487b18505106f70082972851075b0182957b19088298107b18109578ff9788039888039588017b18955908977803977706c98705956618017b1920829951091b821a508217488218208288f882aa18b4a0022c01520738017b15188267107b17587c69188268f8826778196051082152180112977704821810c8870782785108073308280e8277083308012806330801018269e87b18287b1730511902198268f05219011e978704821810c8870782785108073309280e827808330901280633090101826708977704821a10c87a0a82a782aa087b19387b1840951828b4a0022e018215185207a7008219209599109555c8956638520543ff2860829718510768829510977804c858087b18207b190882969577ff9777049877049577017b17956608018269510917821a508217488268f882aa18b4a00230015207528257825908951828b490023201520742955510956610821720ab75ce821908821a829708ac7a0d282d330a829708540726829797a804c88709821a50821748829882990882aa18b4a002340151070833070128053307018210788215708216689511800032009511987b10607b15587b16507b1b207b1948647651085480653484570133082b3309000011db78097b1930c8c70b8457047b1c285107477b1a18551a204b3307510a1b821948c8a908017d9a89aac085aa01959901c8a707ab89f2c87b0b821a188267510764283b81653495cb014911302d8457047b1c285207bf4911488267520721284482174864a87b1b1050203601c108821b10c87b0b821a188267510729826708ae7b238455085205557c6838c9b7077b1a185a1801a5005208b2007b1710648728ad008265208266286457646882193064ab821a485020380174013308015207bd00826c186457821820821928821060821558821650951168320c64757b1b108167307b17087c68387b1882672082682848163030461638017b17407b183882193064ab821a4850203a01220152076a821710c97505955501019555ff5105cc00821738827920330830821740b490023c015107e82842521802129578019877019888017b18102806491110018268207b18408265288168307b1838957601019566ff510628825920821740821838b490023e015107ec330801016487821060821558821650951168320082164064676458821930821a48821b18502040018e003308015207d7825a186467821820821928b4a00242013308015207c18217109a777b17483306ff01821748c867075117ff45825920821740821838b4900244019566015107e52839821738827a18821740821820821928b4a002460133080152077bff33088217087a67308217786738286aff821610821710d87608285eff821710d876082855ff9511d87b10207b15187b161064a6647c5139000011286485828a2064c764987b1b087b1cb4a0024801821c6458821b08647933070152092051061a828a1864c7646864b9821020821518821610951128320a33070182102082151882161095112832009511c07b10387b15307b162864768274827a1084aa01510408520a09286f510a8601826a18c8980b3307510a443303e0003302f000648064852814955c0101c9750595aaffc95c0764c5510a29aab5387d5c590ce984ccff00ac3c0bac2c0d955c0428dd955c0228d8955c0328d36480648c01aabc127dca6408570afe0052070501281801640851041d017b18108265087b190855192037330751091d821a10c89a0864a9017d9a89aac085aa01959901c8a707ab89f2ae57227c6838c975075a18012b51083849012838821710649850204a01ce05ac57e4826828826720828c1882181082190828c600521802119578019877019888017b1828077b173307018268207b18208265288168307b1818957601019566ff51061a825920821720821818b490024c015107ec330701289d00825a18821720821810821908b4a0024e0164783307015208840082179a777b17103306ff01821710c867073308ffaa875d825920821720821818b4900250019566015107e3284f84abff00330ae00051071aae9714c8780a7dab330ac0afab0c51041328f7feab97fadb8709db88085204ebfe826a2882672082ac1801821038821530821628951140320c82168217d8760728088217d87607018210388215308216289511403200827a2882772082ac18320c8279088277829c18320c827a827908648764a82809fe9511e87b177b180847111001003309e80b0133079d09019511c07b17304911382b9517307b1749110801491120491110084911186417649828c89511d87b10207b15187b16107b1751098501330a330b0fe4b90b95bbf1958c0784ccf8c98c079584089a93330cc809017b1c08280995aa01ae9a5b01c8a8057d5557054ebfa7058455075205ebaeba26c8a8058255c8a4068266140c8080808080808080d46505d25c0c520c0995aa10acbae0ae9aa2009aa5c88a0a017dac570c93009555ff95aa01ab53f42807018455ff00821c08c85c0c7cc6330c04aac650330c03aac626330201330c02abc6f60095a001ae90eb00c8080c7dcc3305013306bfafc6c90028ea0095a601ae96d200330201c886067c665125e000426c605225ed0052330c9faf0c6528b80095a601ae96ae00c886067c663302015125f0002b6c665225f4005a330c8faf6c602894009a5a01ac9a27ff287a846ce0003305a000aa5c2a287d956c70ff531c30402873955c1fff33060cac6c0e845cfe003305ee00ab5c5f330cc0afc05995a002ae904fc8080c7dcc581cbf34284c955c0fff561c0241330cc0afc63a95a502ae9530c885057d5c3305bfadc52e95a003ae901fc8080c7dcc5a1cbf25950a01ac9aadfe330a82177b78087b7910282333022810330501280b33050228063305030182177b7a08787210787511330a01017b7a821020821518821610951128320081776489019511b87b10407b15387b16307b19084901018b7a0433090a3304d50801532a7102830033090a951c2e1403000000005917b7d17b1318491110102733007b143303ffe0f505016475977720821818d6870798772d821810ca8702bf2508978a3098aa32ca0a0a98a61198aa1084aafe07966664bf6808978831988830c84a0a7ca67caa01c848087c8b017c8878caff78c6fe78cb0178c89599fc95ccfcac53a95417633697783098883296887b14988811968a64bfa7079777319877309599fec847077c7a017c77951b26c89b0b78ba0178b764870155170a149599ff951826c898088677307887281c9777019599fec847077c78017c77951a26c89a0a78a80178a701951b26c89b0b9a9c0a3309018217088218330a5020580130f8821040821538821630951148320082776489019511b07b10487b15407b16387b1908490101987a043309143304d50801532a71027f330914951c3614084b598638d6c56d347b1818491110102733007b143303ffe0f505016475821718d6750798770b821810ca8702bf2508978a3098aa32ca0a0a98a61198aa1084aafe07966664bf6808978831988830c84a0a7ca67caa01c848087c8b017c8878caff78c6fe78cb0178c89599fc95ccfcac53ac5417633697783098883296887b14988811968a64bfa7079777319877309599fec847077c7a017c77951b24c89b0b78ba0178b764870155170a149599ff951824c898088677307887281c9777019599fec847077c78017c77951a24c89a0a78a80178a701951b24c89b0b9a9c143309018217088218330a50205c0104f782104882154082163895115032009511a07b177b180864177b174033075a017b17489518087b18507b17583307e80e017b1710491118024911309518407b1820491128029517106498285ffb9511c87b10307b15287b16206479957a0784a2f8c9720bacb83c01c9b80c98c70351073201647ac8b90084c8073305aa92147d968966c0856701959901c87505ab09f2330951082184c7f8c8700cc82707c87808017dc78977c085770195cc01c87909ab8cf2140801010101010101013304ff00ff001407ff00ff00ff00ff007b170814020000000001000100140701000100010001007b17c8590764ab2831821a10c84a0a821918c9930b849203821508d2500c98060864a0d25606c86c0c8216ca6c0c98cc30c8c7075202a400510bf200640464b33309c000e69b097b1918979a037b1a103300531b04b784aae007c84a0a644b0182b68562ff98290798660682b508d46909d28909c809098556ff98660782bc10985506d46505d2850585c6ff98660798cc06d46c0c82b618d28c0cc85c0cc8c909856cff98cc07986606d46c0cd28c0c95bb20c8c900ababaa2850ff330751086cc89808017d9a89aac085aa01959901c8a707ab89f22854330a8499fc00979903c894053309c000e6930984990397990301825b95550885bcff98cc0798bb06d4cb0bd28b0b9599f8c8ba0a5209e6821908d29a0898aa08d2a909c898088219ca9808988830c887070182103082152882162095113832006689330a01aba9161409fcffffffffffff7fd8790785770128e7e6330728e2e69511907b177b18087b19107b1a1864177b1750330754017b17589517107b1760330752017b17683307080f017b1720491128024911409518507b18304911380295172064b82828f97c7a7c8babba139599ff9588019577015209f033073200c9ba0732009511e87b10107b15087b16531910698d7a84a207c82706ae671a642c647a648b017cb578a595aa0195ccff95bb01520cf3c82804c929028423f8844807c8360a51083eaea64e9748038480388445f8825b8d88848c38955808018285d00b0bcfc509d4b9097b69956608958808645baca6eb281f647ac8970bacb7242831aea61364480182897b69956608958808aca6f6c83408842907c89a0baeba137c8b78ab95aa019599ff9588015209f3821010821508821695111832008d7a84a207c8270baeb713642c647a0178a895ccff95aa01520cf8c92909849af8c8ba0aaeab22978238140c0001010101000000d6c202972c20d42c0c017bbc95bb08acabfb849907c89a0bacba05280d78a89599ff95aa015209f83200212422a29288228084a424912422499244a488249288488d4884884892492991884222914824922449241129442422858844a4109188424421222244a410918808914412924a2a490049524a4902a8005a44441121858444449424128594492491248914892489d44812124932229224444a4644922449129224214944449284249124055001944a4a49024809a02459444485242121499224804495269224222549a9495248a4ca14490a494aa2004a95490590a45a925448284948444449225104900012522611499224912212492222359208892499842429c948842449482422248924244922490248892489244994440aa002289594920490124049b288880a49424292245592aa504a15aa49529294249592a424494992d4240949529254924a49924a499248890490924852932424494952492a25492a2549222512404a22494d929024254925a994449592244992920002484a92aa298592942415928484949090522a09a092009244928424494a4d920a254921014492a44a0a2589420490001a1151229188884821222292242222528888888888888848212222222222222285888888888888881412111111119142225192a48a440009a08c248988888888888888888888888848242289121111292401944492888448424444924444244944441291241111294992a424128988a88888482122229224222252888888248988881412119124859244210248008d882891484444a490888888889224551249004b24294a92549292082080444492242149481222125292148988a8244992444454494102482489482449225112129184244852350989249244925492249964926445441442481211512992a424499244929424121111112191482441922a9a244424110124244992324948922441220949449254b222224a841012492a4592942449924892a4449224255452444449928844229190902a912888442248242212898848442412212242441091aa9144222291888844442211222244041191144444244991111145841012292121a5548a24050920499224019426292825259564124002689294248094a428a15290aa4a25499224499224495405c992a44a4a9292a42409221192142429a592244992244992244a2a484a5292a4d292a49204950425498204902449505292a40421842425092a094a920409204992a0a4244909420849524849122929884a5252929425c924259914244952928a24499232a4a490244992144248522529552529a5542a49aa6aa49424254935498a929048122149928a3425493125a91594a24442224922892449120989244924481295aaaa14514522225210491209202193244284488424229144498248922449221240426a92448810899044249248124492900425522202c824891021122189489248224192544644942429952a4849992429492a2549922499240549529254494a924c542949922429092080a424a99a5228494952a124144a925449aa8252aaa09a24254929852291d2841225219124429224494a5249324a4222498424494a9224a584244929252555414a49525215944a5249524a29292829494aaa8252924449a910342949924452924492484a22492489644aa494a4a04c49525205a924954292a494949624499224194952412495324922a9949082841092a43405c924494a92925441490d952429a594149494242555412949a2a454089a94244922294922492425912492443225524a5250a62429a982942449924408494144211251c5244992940821298828449224922449244a92242549a624494224494a2249a9a44c128924a59232494a92904892284992942465499290929024494925254949486a92284992922424499228c992244929892429a504494a9224099192544a9048499254929444242941924c24494891246592249324215992944a12242909494a26912424254942a2a4244992244905a552a894245592d42429492a498aa4445499a4a4449252aaa9881449a2242d499224522948922491a46a922493242149928412954c922421292249499224924c922a95495292522a95941842122912a992a42849921452222549520a204912659124919424492452124924854292444a2824691491228a24224992a28824494992225149955296244b926a922449089200122258922449924492a4242529492491244952921a495249529226492a48926a92244908490009112c4992244924494a529292441249922425a991249524256992a4822429a5449284449248499292441225a5244949922549020802480001944a92242929494445921491962449922449922449922449c99224154924599224499224259924950490a4a424259244422249a45492a45292a224d54a92244992a4922529299594569224a924494a25a925499204906449924a12") + + preimage = Preimage.extract(new_service_preimage) + + solicit_instruction = Instruction.from_json({'Solicit': {'hash': '0xcbc63dc2acb86bd8967453ef98fd4f2be2f26d7337a0937958211c128a18b442', 'len': 2}}) + + create_instruction = Instruction.from_json( + { + 'CreateService': { + 'code_hash': blake2b_256_hash(new_service_preimage), + 'code_len': len(new_service_preimage), + 'endowment': 100000, + 'memo': '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + 'min_item_gas': 1000000, + 'min_memo_gas': 1000000, + 'registration': registration + } + } + ) + + random_storage_instruction = Instruction.from_json( + {'RandomStorageRefine': { + 'seed': 3081892978, + 'nb_items': 6 + }} + ) + + export_instruction = Instruction.from_json( + {'Export': { + 'data': [b'test'], + }} + ) + + zombify_instruction = Instruction.from_json({'Zombify': {'ejector': 0}}) + + eject_instruction = Instruction.from_json( + {'Eject': {'target': 0, 'code_hash': '0x6c63e601e26279872a93b9b443aa52ad1c26e795647f63c0b7e0abff0d3680da'}} + ) + + extrinsic = [bytes(100), bytes(200), bytes(400)] + + work_package = await create_bootservice_workpackage(client, create_instruction, extrinsic) + + print(f"Creating service '{preimage.program_name}'...") + await client.submitWorkPackage(0, work_package, extrinsic) + + new_service = await client.subscribeServiceValue(bootstrap_service_id, b'created') + async for data in new_service: + print("Waiting for new service ID ...") + if data: + new_service_id = int.from_bytes(data, byteorder='little') + print(f'Service ID = {data[::-1].hex()} ({new_service_id})') + break + + # Provide preimage + await client.submitPreimage(new_service_id, new_service_preimage) + + sub_request = await client.subscribeServiceRequest(new_service_id, blake2b_256_hash(new_service_preimage), len(new_service_preimage)) + async for data in sub_request: + print(f"Waiting for preimage ... {data}") + if len(data) == 1: + break + + # service_registry = await get_service_registry(client) + + work_package = await create_empty_workpackage(client) + work_package.items.append( + WorkItem( + accumulate_gas_limit=10000000, + code_hash=blake2b_256_hash(new_service_preimage), + # code_hash=service_registry.services[0][1].code_hash, + export_count=0, + extrinsic=[], + import_segments=[], + payload=b'Testing 1, 2, 3', + refine_gas_limit=5000000000, + service=new_service_id + # service=service_registry.services[0][1].id + ) + ) + print('Submitting work package for new service...') + await client.submitWorkPackage(0, work_package, extrinsic) + + last_value = await client.subscribeServiceValue(new_service_id, b'last') + print("Waiting for new last value ...") + async for data in last_value: + if data: + print(f'Last value = {data}') + break + + print('Done!') + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/pyjamaz/app.py b/pyjamaz/app.py index e6b9c1be..f73d0e7b 100644 --- a/pyjamaz/app.py +++ b/pyjamaz/app.py @@ -144,6 +144,15 @@ async def import_block_from_bytes(self, data): logging.info(f"Syncing in progress, current timeslot={self.working_state.timeslot.number}") + async def import_queue_add_blocks(self, blocks: List[Block], process: bool=False, on_success: MESSAGE_TYPES=None, on_failure: MESSAGE_TYPES=None): + async with self.import_lock: + for block in blocks: + self.import_queue.append(block) + + if process: + await self.process_import_queue(on_success=on_success, on_failure=on_failure) + + async def import_block_from_json(self, data): DEBUG and logging.debug(f"📦 Importing block from json") block = Block.from_json(data) @@ -152,35 +161,47 @@ async def import_block_from_json(self, data): async def requested_blocks_from_json(self, data): block_list = [Block.from_json(block_data) for block_data in data] - for block in block_list: - self.import_queue.append(Block.from_codec_type(block)) - logging.info(f"📦 Queue block requested #{block.header.timeslot}") + async with self.import_lock: + for block in block_list: + self.import_queue.append(Block.from_codec_type(block)) + logging.info(f"📦 Queue block requested #{block.header.timeslot}") await self.process_import_queue() async def requested_blocks_from_bytes(self, data): - block_list = Vec(Block.to_codec_def()).new() - block_list.decode(JamBytes(data)) - for block_bytes in block_list: - block = Block.from_codec_type(block_bytes) - self.import_queue.append(block) + async with self.import_lock: + block_list = Vec(Block.to_codec_def()).new() + block_list.decode(JamBytes(data)) + for block_bytes in block_list: + block = Block.from_codec_type(block_bytes) + self.import_queue.append(block) await self.process_import_queue() - async def process_import_queue(self): + async def process_import_queue(self, on_success:MESSAGE_TYPES=None, on_failure:MESSAGE_TYPES=None): async with self.import_lock: sorted_blocks = sorted(self.import_queue, key=lambda x: x.header.timeslot) self.import_queue = [] - for block in sorted_blocks: - # TODO: protocol should only import blocks from this point on -> fix the block_request - if self.working_state.timeslot.number >= block.header.timeslot: - DEBUG and logging.debug(f" TEMP BREAK block from process_import_queue: {block.header.timeslot}") - continue + try: + for block in sorted_blocks: + # TODO: protocol should only import blocks from this point on -> fix the block_request + if self.working_state.timeslot.number >= block.header.timeslot: + DEBUG and logging.debug(f" TEMP BREAK block from process_import_queue: {block.header.timeslot}") + continue - await self.import_block(block) - DEBUG and logging.debug(f'✅ Block {block.header.timeslot} successfully imported from process_import_queue.') + await self.import_block(block) + DEBUG and logging.debug( + f'✅ Block {block.header.timeslot} successfully imported from process_import_queue.') + + if on_success: + await self.pubsub.publish(PubSubSignal(topic=on_success, data=None)) + + except Exception as e: + if on_failure: + await self.pubsub.publish(PubSubSignal(topic=on_failure, data=None)) + logging.error(f"Error processing import queue: {e}") async def initialize(self, header: Optional[Header] = None, produce=False): @@ -211,8 +232,6 @@ async def initialize(self, header: Optional[Header] = None, produce=False): self.working_state = self.retrieve_jam_state() DEBUG and logging.debug(f"Updated working state to state_root={format_hash(self.working_state.state_root)}") - else: - DEBUG and logging.debug("StateStorage: State already matches requested state root, no updating required") def retrieve_ancestor_headers(self, block_hash: bytes) -> List[Header]: """ @@ -715,6 +734,9 @@ async def store_block_header(self, header: Header): self.block_db.put( b'block_number:' + header.hash, header.timeslot.to_bytes(length=4, byteorder='little') ) + self.block_db.put( + b'block_child:' + header.parent, header.hash + ) def retrieve_block(self, timeslot: int) -> Optional[Block]: block_data = self.block_db.get(b'block:' + timeslot.to_bytes(length=4, byteorder='little')) @@ -743,6 +765,9 @@ async def store_finalized_head(self, block_hash: bytes): def retrieve_block_hash(self, timeslot: int) -> Optional[bytes]: return self.block_db.get(b'block_hash:' + timeslot.to_bytes(length=4, byteorder='little')) + def retrieve_block_child_hash(self, block_hash: bytes) -> Optional[bytes]: + return self.block_db.get(b'block_child:' + block_hash) + def should_produce_block(self, timeslot: int, safrole_state: SafroleState) -> bool: slot_phase_index = timeslot % EPOCH_TIMESLOTS @@ -926,24 +951,24 @@ async def produce_block( ring_public_keys = [v.bandersnatch for v in safrole_state.validators] ring_context = RingContext(self.config.ring_data, ring_public_keys) - self.block_extrinsic.add_own_ticket( - ring_context, entropy, self.config.keys.bandersnatch, self.get_author_index() + await self.block_extrinsic.add_own_ticket( + ring_context, entropy, self.config.keys.bandersnatch, self.get_author_index(), pubsub=self.pubsub ) - self.block_extrinsic.add_own_ticket( - ring_context, entropy, self.config.keys.bandersnatch, self.get_author_index() + await self.block_extrinsic.add_own_ticket( + ring_context, entropy, self.config.keys.bandersnatch, self.get_author_index(), pubsub=self.pubsub ) - self.block_extrinsic.add_own_ticket( - ring_context, entropy, self.config.keys.bandersnatch, self.get_author_index() + await self.block_extrinsic.add_own_ticket( + ring_context, entropy, self.config.keys.bandersnatch, self.get_author_index(), pubsub=self.pubsub ) extrinsic = Extrinsic( - tickets=self.block_extrinsic.collect_tickets(), + tickets=await self.block_extrinsic.collect_tickets(), disputes=ExtrinsicDisputes(verdicts=[], culprits=[], faults=[]), preimages=self.block_extrinsic.collect_preimages(self.working_state.services), assurances=self.block_extrinsic.collect_assurances(), - guarantees=self.block_extrinsic.collect_guarantees(), + guarantees=await self.block_extrinsic.collect_guarantees(), ) header = Header( diff --git a/pyjamaz/cli.py b/pyjamaz/cli.py index 415dc683..66ebc8c3 100644 --- a/pyjamaz/cli.py +++ b/pyjamaz/cli.py @@ -1,5 +1,6 @@ import bisect import logging +import re import traceback from asyncio import CancelledError from datetime import datetime, timezone @@ -27,15 +28,14 @@ from pyjamaz.logger import setup_logging from pyjamaz.models.app import Trace, TraceGenesis from pyjamaz.models.state import STORAGE_KEY_MAPPING, ServiceAccount -from pyjamaz.rpc.ws_server import start_rpc_server, WebSocketServer +from pyjamaz.transport.rpc.ws_server import start_rpc_server, WebSocketServer from pyjamaz.runtime.node_runtime import NodeRuntime from pyjamaz.settings import GP_VERSION, APP_VERSION, STORAGE_ENGINE, DEBUG from pyjamaz.storage import InMemoryStorageEngine, RocksDBStorageEngine from pyjamaz.models.block import Block, Header, Extrinsic from pyjamaz.fuzzer import FuzzerMessage, InitializeMessage, FuzzerTarget, FuzzerSession, AncestryItem -from pyjamaz.transport.cert import generate_cert, write_cert -from pyjamaz.transport.protocol_fs import FSProtocol -from pyjamaz.transport.protocol_jamnp_s import JAMNPS +from pyjamaz.transport.cert import generate_cert, read_cert_public_key, write_cert +from pyjamaz.transport.jamnp_s.network import JAMNPS from pyjamaz.transport.pubsub import PubSub, PubSubSignal from pyjamaz.utils import format_hash, quic_peer_id @@ -124,21 +124,6 @@ async def cli_import_block(self, block: Block, dry_run=False): return cli_import_block -def wrap_produced_block_jamnp(app: PyjamazApp, traces_dir, np_protocol: JAMNPS): - async def produced_block_jamnp(block: Block): - await np_protocol.broadcast_block(block) - - return produced_block_jamnp - - -def wrap_produced_block_fs(app: PyjamazApp, traces_dir, fs_protocol: FSProtocol): - async def produced_block_fs(block: Block): - await app.import_block(block) - await fs_protocol.broadcast_block(block) - - return produced_block_fs - - async def initialize_app( read_state=True, storage_engine='memory', @@ -237,6 +222,7 @@ async def run(seed, port, ts, culprit, block_dir, record_traces, custom_db_path, # Note: Add packages that need a different logging level here log_package_overrides = { "pyjamaz.transport": log_level, + #"pyjamaz.transport.jamnp_s": logging.DEBUG, "quic": logging.WARNING, "numba": logging.WARNING, "numba.core": logging.WARNING @@ -254,9 +240,7 @@ async def run(seed, port, ts, culprit, block_dir, record_traces, custom_db_path, db_path = custom_db_path or default_db_path - network_bootstrap = ts is None - if network_bootstrap: - ts = 0 + ts = ts or 0 #TODO: currently it is not possible to provide a hard unix timestamp (only deltas) current_time = time.time() @@ -279,7 +263,6 @@ async def run(seed, port, ts, culprit, block_dir, record_traces, custom_db_path, for header in app.retrieve_ancestor_headers(app.state_storage.finalized_block_hash): app.state_storage.add_ancestor(header) - app.network_bootstrap = network_bootstrap common_era_time = datetime.fromtimestamp(app.config.common_era, tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC") if replay_blocks: @@ -296,6 +279,14 @@ async def run(seed, port, ts, culprit, block_dir, record_traces, custom_db_path, logging.info(f'🌐 Peer ID: {quic_peer_id(app.config.keys.ed25519.public_key)}') logging.info(f'🔑 Bandersnatch public: {format_hash(app.config.keys.bandersnatch.public_key)}') logging.info(f'🔑 Ed25519 public: {format_hash(app.config.keys.ed25519.public_key)}') + #TODO: for now we assume we are either in the validator pool or are a listening node + validator_index = app.get_validator_index() + if validator_index is None: + logging.warning( + "⚠️ Local key not in validator pool; acting as non participating node" + ) + else: + logging.info(f"🧩 Validator pool index: #{validator_index}") logging.info(f'🗓️ Common Era: {app.config.common_era} ({common_era_time})') logging.info(f'🌲 State trie root: {format_hash(app.working_state.state_root)}') logging.info(f'📦 Finalized block: {format_hash(app.state_storage.finalized_block_hash)}') @@ -313,6 +304,10 @@ async def run(seed, port, ts, culprit, block_dir, record_traces, custom_db_path, try: async with anyio.create_task_group() as tg: + # Create and start runtime + app.runtime = NodeRuntime(app) + app.runtime.start(tg) + # TODO: we need to start this manually in all event loops, make an AppFactory that handles this in a generic way # Create a subscriber to process incoming messages (fx from a protocol) tg.start_soon(app.pubsub.process_messages) @@ -320,47 +315,53 @@ async def run(seed, port, ts, culprit, block_dir, record_traces, custom_db_path, # Start WebSocket server tg.start_soon(start_rpc_server, rpc_server) - if False and block_dir: - # TODO remove - logging.info(f"👀 Watching directory: {block_dir} for new blocks...") - fs_protocol = FSProtocol(block_dir, app) - app.protocol = fs_protocol - app.pubsub.subscribe(MESSAGE_TYPES.PRODUCED_BLOCK, wrap_produced_block_fs(app, record_traces, fs_protocol)) - app.pubsub.subscribe(MESSAGE_TYPES.RECEIVED_BLOCK, app.import_block_from_json) - app.pubsub.subscribe(MESSAGE_TYPES.REQUESTED_BLOCKS, app.requested_blocks_from_json) - tg.start_soon(fs_protocol.listen) - else: - certificate_file = os.path.join(db_path, "cert.pem") - pk_file = os.path.join(db_path, "cert.key") - nps_protocol = JAMNPS(host, port, certificate_file, pk_file, app) - app.protocol = nps_protocol - app.pubsub.subscribe(MESSAGE_TYPES.PRODUCED_BLOCK, wrap_produced_block_jamnp(app, record_traces, nps_protocol)) - app.pubsub.subscribe(MESSAGE_TYPES.RECEIVED_BLOCK, app.import_block_from_bytes) - app.pubsub.subscribe(MESSAGE_TYPES.REQUESTED_BLOCKS, app.requested_blocks_from_bytes) - tg.start_soon(nps_protocol.listen) - - for validator in app.working_state.safrole.validators: - # The validators' IP-layer endpoints are given as IPv6/port combinations, - # to be found in the first 18 bytes of validator metadata, with the first 16 bytes being the IPv6 address and - # the latter 2 being a little endian representation of the port. - - validator_port = validator.get_metadata_port() - validator_address = validator.get_metadata_ipaddress() - - if validator.ed25519 == app.config.keys.ed25519.public_key: - DEBUG and logging.debug( - f'Skipping own node ({validator_address}:{validator_port})' - ) - continue - - DEBUG and logging.debug(f'Connecting to node {validator_address}:{validator_port}') - tg.start_soon(nps_protocol.connect, validator_address, validator_port) + certificate_file = os.path.join(db_path, "cert.pem") + pk_file = os.path.join(db_path, "cert.key") + await ensure_certificate_matches_seed(db_path, seed) + nps_protocol = JAMNPS(host, port, certificate_file, pk_file, app) + app.protocol = nps_protocol + tg.start_soon(nps_protocol.listen) + tg.start_soon(nps_protocol.check_connections) + + if bootnode: + # logging.debug(f'Connecting to node {validator_address}:{validator_port}') + # tg.start_soon(nps_protocol.connect, validator_address, validator_port) + + # ecjn4brac2kgu25kiykefww6p6ai7noueo6p5af5tnwjgra4eisya@172.16.238.11:40001 + conn = re.match( + r"^(?P[A-Za-z0-9]+)" + r"@" + r"(?P(?:\d{1,3}\.){3}\d{1,3})" + r":" + r"(?P\d{1,5})$", + bootnode, + ) - await anyio.sleep(ts - time.time()) + logging.debug(f'Connecting to bootnode {conn["key"]} at {conn["addr"]}:{conn["port"]}') + try: + await nps_protocol.connect(conn["addr"], int(conn["port"]), None) + except Exception as exc: + traceback.print_exc() + # else: + # # for validator in app.state.safrole.validators: + # # # The validators' IP-layer endpoints are given as IPv6/port combinations, + # # # to be found in the first 18 bytes of validator metadata, with the first 16 bytes being the IPv6 address and + # # # the latter 2 being a little endian representation of the port. + # # + # # validator_port = validator.get_metadata_port() + # # validator_address = validator.get_metadata_ipaddress() + # # + # # if validator.ed25519 == app.config.keys.ed25519.public_key: + # # logging.debug( + # # f'Skipping own node ({validator_address}:{validator_port})' + # # ) + # # continue + # # + # # logging.debug(f'Connecting to node {validator_address}:{validator_port}') + # # tg.start_soon(nps_protocol.connect, validator_address, validator_port) + # #tg.start_soon(nps_protocol.connect, "127.0.0.1", 40001) - # Create and start runtime - app.runtime = NodeRuntime(app) - app.runtime.start(tg) + await anyio.sleep(ts - time.time()) except (KeyboardInterrupt, CancelledError): logging.info("Stopping node...") @@ -414,13 +415,33 @@ async def init_certificate(db_path, seed): pk_pem, cert_pem = generate_cert( keys, ips="127.0.0.1", #TODO: hardcoded for now - alternative_name="e3r2oc62zwfj3crnuifuvsxvbtlzetk4o5qyhetkhagsc2fgl2oka", ) pk_file = os.path.join(db_path, "cert.key") pem_file = os.path.join(db_path, "cert.pem") write_cert(pk_pem, pk_file, cert_pem, pem_file) +async def ensure_certificate_matches_seed(db_path, seed): + cert_file = os.path.join(db_path, "cert.pem") + pk_file = os.path.join(db_path, "cert.key") + expected_public_key = Keys.from_seed(bytes.fromhex(seed[2:])).ed25519.public_key + + if not os.path.exists(cert_file) or not os.path.exists(pk_file): + logging.info("🔐 JAMNP-S certificate missing; generating a new certificate") + await init_certificate(db_path, seed) + return + + actual_public_key = read_cert_public_key(cert_file) + if actual_public_key == expected_public_key: + return + + logging.warning( + "🔐 JAMNP-S certificate key does not match the provided seed; regenerating certificate " + f"(cert={format_hash(actual_public_key)}, expected={format_hash(expected_public_key)})" + ) + await init_certificate(db_path, seed) + + @main.command() @click.option('--seed', 'seed', type=str, help="Seed to use for validator keys") @click.option('--chainspec', 'chainspec', type=click.Choice(['dev', 'docker']), help="Chainspec to use as genesis", default='dev', show_default=True) diff --git a/pyjamaz/constants.py b/pyjamaz/constants.py index b3166da6..51580396 100644 --- a/pyjamaz/constants.py +++ b/pyjamaz/constants.py @@ -38,8 +38,6 @@ class MESSAGE_TYPES(Enum): PRODUCED_BLOCK = "PRODUCED_BLOCK" - RECEIVED_BLOCK = "RECEIVED_BLOCK" - REQUESTED_BLOCKS = "REQUESTED_BLOCKS" STATISTICS = "statistics" SERVICE_ACCOUNT = "service_account" @@ -50,6 +48,12 @@ class MESSAGE_TYPES(Enum): FINALIZED_BLOCK = "finalized_block" WORK_PACKAGE_STATUS = "work_package_status" + TICKET_ADD = "ticket_add" + + CE128_SUCCESS = "CE128_SUCCESS" + CE128_FAILURE = "CE128_FAILURE" + + PVM_MARSHALLING_OFFSET_ACCUMULATE = 5 PVM_MARSHALLING_OFFSET_TRANSFER = 10 PVM_MARSHALLING_OFFSET_REFINE = 0 diff --git a/pyjamaz/graypaper_constants.py b/pyjamaz/graypaper_constants.py index 7c3bbe13..05aae0af 100644 --- a/pyjamaz/graypaper_constants.py +++ b/pyjamaz/graypaper_constants.py @@ -45,6 +45,11 @@ PVM_INIT_ZONE_SIZE = 2**16 #ZZ COMMON_ERA = 1735732800 +#TODO: TEMP JAMNP HACK!!!!!! +# import datetime +# dt = datetime.datetime(2025,1,1,12,0,0, tzinfo=datetime.timezone.utc) +# COMMON_ERA = int(dt.timestamp()) + from pyjamaz.settings import TEST_SUITE if TEST_SUITE == 'tiny': diff --git a/pyjamaz/logger.py b/pyjamaz/logger.py index 52d1f141..5763e6d1 100644 --- a/pyjamaz/logger.py +++ b/pyjamaz/logger.py @@ -15,6 +15,10 @@ class LogFormatter(logging.Formatter): logging.CRITICAL: "🚨" } + def __init__(self, width=30, *args, **kwargs): + super().__init__(*args, **kwargs) + self.width = width + def format(self, record): # Prepend the appropriate icon based on log level icon = self.icons.get(record.levelno, "") @@ -25,12 +29,27 @@ def format(self, record): if record.levelno > logging.INFO: record.msg = click.style(f'{record.msg}', fg='red') + + combo = f"{record.filename}:{record.funcName}" + record.funcName = (combo[: self.width]).ljust(self.width) + return super().format(record) def setup_logging(log_level=logging.INFO, package_loggers=None): - log_format = click.style("%(asctime)s.%(msecs)03d", fg=(80, 80, 80)) + " %(message)s" - formatter = LogFormatter(log_format, datefmt="%Y-%m-%d %H:%M:%S") + #log_format = click.style("%(asctime)s.%(msecs)03d", fg=(80, 80, 80)) + " %(message)s" + #formatter = LogFormatter(log_format, datefmt="%Y-%m-%d %H:%M:%S") + + time_style = click.style("%(asctime)s.%(msecs)03d", fg=(80, 80, 80)) + + log_format = ( + f"{time_style} " + "%(funcName)s " + "%(message)s" + ) + + # only want HH:MM:SS, so change datefmt + formatter = LogFormatter(width=50, fmt=log_format, datefmt="%H:%M:%S") # Configure logging handler = logging.StreamHandler() diff --git a/pyjamaz/runtime/extrinsics.py b/pyjamaz/runtime/extrinsics.py index 165ad119..cbe45095 100644 --- a/pyjamaz/runtime/extrinsics.py +++ b/pyjamaz/runtime/extrinsics.py @@ -1,16 +1,19 @@ +import asyncio import logging from typing import Dict, List, Optional from bandersnatch_vrfs import RingContext, vrf_output -from pyjamaz.graypaper_constants import TICKET_ENTRIES, EPOCH_TIMESLOTS, TICKET_SUBMISSION_END_SLOT, \ - MAXIMUM_EXTRINSIC_TICKETS +from pyjamaz.constants import MESSAGE_TYPES +from pyjamaz.graypaper_constants import TICKET_ENTRIES, MAXIMUM_EXTRINSIC_TICKETS, TICKET_SUBMISSION_END_SLOT, \ + EPOCH_TIMESLOTS from pyjamaz.hashing import blake2b_256_hash -from pyjamaz.models.block import TicketEnvelope, Guarantee, Assurance, Preimage +from pyjamaz.models.block import TicketEnvelope, Guarantee, Assurance, Preimage, Block from pyjamaz.models.common import TicketBody, WorkPackage from pyjamaz.models.state import ServicesState from pyjamaz.models.stf_output import SafroleErrorCode from pyjamaz.signing import BandersnatchKeypair +from pyjamaz.transport.pubsub import PubSub, PubSubSignal from pyjamaz.utils import vrf_input_ticket_seal, format_hash @@ -25,6 +28,8 @@ def __init__(self, ring_data: bytes): self.preimage_queue: List[Preimage] = [] self.ring_data = ring_data + self._ticket_queue_lock = asyncio.Lock() + def create_ticket_body(self, ticket_data: TicketEnvelope, ring_context: RingContext, entropy: bytes) -> TicketBody: if ticket_data.attempt >= TICKET_ENTRIES: raise ValueError(SafroleErrorCode.bad_ticket_attempt) @@ -42,16 +47,18 @@ def create_ticket_body(self, ticket_data: TicketEnvelope, ring_context: RingCont return TicketBody(id=ring_vrf_output, attempt=ticket_data.attempt) - def add_ticket(self, ticket_data: TicketEnvelope, ring_public_keys: List[bytes], entropy: bytes): + async def add_ticket(self, ticket_data: TicketEnvelope, ring_public_keys: List[bytes], entropy: bytes): ring_context = RingContext(self.ring_data, ring_public_keys) ticket_body = self.create_ticket_body(ticket_data, ring_context, entropy) - self.tickets_queue[ticket_body.id] = ticket_data + async with self._ticket_queue_lock: + self.tickets_queue[ticket_body.id] = ticket_data def can_add_own_ticket(self, timeslot: int) -> bool: return len(self.own_tickets_next) < TICKET_ENTRIES and timeslot % EPOCH_TIMESLOTS < TICKET_SUBMISSION_END_SLOT - def add_own_ticket( - self, ring_context: RingContext, entropy: bytes, keypair: BandersnatchKeypair, author_index: int + async def add_own_ticket( + self, ring_context: RingContext, entropy: bytes, keypair: BandersnatchKeypair, author_index: int, + epoch_index: int = None, pubsub: PubSub = None ): if len(self.tickets_queue) > TICKET_ENTRIES: @@ -75,10 +82,16 @@ def add_own_ticket( logging.info(f'🎫 Generated ticket: {format_hash(ticket_id)}') logging.DEBUG and logging.debug(f'Generated ticket: id = {format_hash(ticket_id)} with entropy {format_hash(entropy)}') - self.tickets_queue[ticket_id] = ticket + async with self._ticket_queue_lock: + self.tickets_queue[ticket_id] = ticket self.own_tickets_next.append(ticket_id) - def collect_tickets(self) -> List[TicketEnvelope]: + # Notify new ticket is added + if pubsub and epoch_index is not None: + await pubsub.publish(PubSubSignal(topic=MESSAGE_TYPES.TICKET_ADD, data=[epoch_index, attempt, signature])) + + + async def collect_tickets(self) -> List[TicketEnvelope]: """ Collect tickets to include in a block @@ -87,11 +100,12 @@ def collect_tickets(self) -> List[TicketEnvelope]: List[TicketEnvelope] """ - collected_tickets = sorted(self.tickets_queue.items())[:MAXIMUM_EXTRINSIC_TICKETS] + async with self._ticket_queue_lock: + collected_tickets = sorted(self.tickets_queue.items())[:MAXIMUM_EXTRINSIC_TICKETS] - # Remove from queue - for key in [key for key, _ in collected_tickets]: - self.tickets_queue.pop(key) + # Remove from queue + for key in [key for key, _ in collected_tickets]: + self.tickets_queue.pop(key) return [ticket for _, ticket in collected_tickets] @@ -101,24 +115,27 @@ def is_own_ticket(self, ticket_id: bytes) -> bool: def own_ticket_count(self) -> int: return len(self.own_tickets_next) - def clear_own_tickets(self): - for ticket_id in self.own_tickets_next: - del self.tickets_queue[ticket_id] + async def clear_own_tickets(self): + async with self._ticket_queue_lock: + for ticket_id in self.own_tickets_next: + del self.tickets_queue[ticket_id] self.own_tickets_next = [] - def clear_tickets(self): - self.tickets_queue = {} + async def clear_tickets(self): + async with self._ticket_queue_lock: + self.tickets_queue = {} self.own_tickets_next = [] - def process_epoch_change(self): + async def process_epoch_change(self): self.own_tickets_current = self.own_tickets_next self.own_tickets_next = [] - self.tickets_queue = {} + async with self._ticket_queue_lock: + self.tickets_queue = {} def add_guarantee(self, guarantee: Guarantee): self.guarentees_queue[guarantee.report.hash()] = guarantee - def collect_guarantees(self) -> List[Guarantee]: + async def collect_guarantees(self) -> List[Guarantee]: guarentees = list(self.guarentees_queue.values()) self.guarentees_queue = {} return guarentees diff --git a/pyjamaz/runtime/pipelines/accumulate.py b/pyjamaz/runtime/pipelines/accumulate.py index 88ec4d74..4ab74541 100644 --- a/pyjamaz/runtime/pipelines/accumulate.py +++ b/pyjamaz/runtime/pipelines/accumulate.py @@ -117,7 +117,7 @@ async def _timeslot_worker(self) -> None: ) # Process tickets - self.app.block_extrinsic.process_epoch_change() + await self.app.block_extrinsic.process_epoch_change() DEBUG and logging.debug( f"Current tickets {[i.hex() for i in self.app.block_extrinsic.own_tickets_current]}" ) @@ -161,7 +161,7 @@ async def _timeslot_worker(self) -> None: # Rollback state from DB self.app.working_state = self.app.retrieve_jam_state() # TODO Make transactional - self.app.block_extrinsic.clear_tickets() + await self.app.block_extrinsic.clear_tickets() else: logging.info(f'💤 Waiting for block #{timeslot} | epoch #{epoch} | phase #{phase}') diff --git a/pyjamaz/settings.py b/pyjamaz/settings.py index 5f848d04..20ec4987 100644 --- a/pyjamaz/settings.py +++ b/pyjamaz/settings.py @@ -35,6 +35,10 @@ PVM_INTERPRETER = os.getenv("PVM_INTERPRETER", "NUMBA_AOT") RPC_SERVER_MAX_SIZE = 30 * 1024 * 1024 +# validator overrides for JAMNP-S +# Keys are validator Ed25519 public key hex strings ( with or without 0x) +# Values can be either "host:port" or ("host", port), or None to ignore connections (for debugging purposes) +VALIDATOR_ENDPOINT_OVERRIDES = {} GUARANTEE_SIGNATURE_WAIT_PERIOD = 2 diff --git a/pyjamaz/transport/cert.py b/pyjamaz/transport/cert.py index d46e490d..71f07823 100644 --- a/pyjamaz/transport/cert.py +++ b/pyjamaz/transport/cert.py @@ -1,3 +1,72 @@ +# from cryptography import x509 +# from cryptography.x509.oid import ExtendedKeyUsageOID as EKU, NameOID +# from cryptography.hazmat.primitives.asymmetric import ed25519 +# from cryptography.hazmat.primitives import serialization +# from ipaddress import ip_address +# from datetime import datetime, timedelta +# +# +# def generate_cert(keys, ips: str, alternative_name: str): +# priv = ed25519.Ed25519PrivateKey.from_private_bytes(keys.ed25519.private_key) +# +# sans = [x509.IPAddress(ip_address(ip.strip())) +# for ip in ips.split(",") if ip.strip()] +# sans.append(x509.DNSName(alternative_name)) +# +# name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "jamnps-node")]) +# +# cert = ( +# x509.CertificateBuilder() +# .subject_name(name).issuer_name(name) +# .public_key(priv.public_key()) +# .serial_number(x509.random_serial_number()) +# .not_valid_before(datetime.utcnow() - timedelta(minutes=5)) +# .not_valid_after(datetime.utcnow() + timedelta(days=365)) +# # ---- LEAF EXTENSIONS – **none** of them critical ------------------- +# # .add_extension( +# # x509.BasicConstraints(ca=False, path_length=None), critical=False +# # ) +# # .add_extension( +# # x509.KeyUsage( +# # digital_signature=True, +# # key_encipherment=False, +# # content_commitment=False, +# # data_encipherment=False, +# # key_agreement=False, +# # key_cert_sign=False, +# # crl_sign=False, +# # encipher_only=False, +# # decipher_only=False, +# # ), +# # critical=False, +# # ) +# # .add_extension( +# # x509.ExtendedKeyUsage([EKU.SERVER_AUTH]), critical=False +# # ) +# .add_extension( +# x509.SubjectAlternativeName(sans), critical=False +# ) +# .sign(priv, algorithm=None) +# ) +# +# return ( +# priv.private_bytes( +# serialization.Encoding.PEM, +# serialization.PrivateFormat.PKCS8, +# serialization.NoEncryption(), +# ), +# cert.public_bytes(serialization.Encoding.PEM), +# ) +# +# +# def write_cert(pk_pem, pk_file, cert_pem, cert_file): +# +# with open(pk_file, 'wb') as f: +# f.write(pk_pem) +# +# with open(cert_file, 'wb') as f: +# f.write(cert_pem) + from cryptography import x509 from cryptography.x509.oid import ExtendedKeyUsageOID as EKU, NameOID from cryptography.hazmat.primitives.asymmetric import ed25519 @@ -5,50 +74,47 @@ from ipaddress import ip_address from datetime import datetime, timedelta +from cryptography import x509 +from cryptography.x509.oid import NameOID -def generate_cert(keys, ips: str, alternative_name: str): - priv = ed25519.Ed25519PrivateKey.from_private_bytes(keys.ed25519.private_key) +from pyjamaz.utils import quic_peer_id - sans = [x509.IPAddress(ip_address(ip.strip())) - for ip in ips.split(",") if ip.strip()] - sans.append(x509.DNSName(alternative_name)) - name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "jamnps-node")]) +def generate_cert(keys, ips: str): + priv = ed25519.Ed25519PrivateKey.from_private_bytes(keys.ed25519.private_key) + + subject = x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"rcgen self signed cert"), + ]) + issuer = x509.Name([ + x509.NameAttribute(NameOID.COMMON_NAME, u"rcgen self signed cert"), + ]) + serial_numer = 76354585232599687591316365089471291226684720524 + not_valid_before = datetime(1975, 1, 1, 0, 0) + not_valid_after = datetime(4096, 1, 1, 0, 0) + peer_id = quic_peer_id(keys.ed25519.public_key) + #print(peer_id) + ext = x509.SubjectAlternativeName(x509.GeneralNames([x509.DNSName(peer_id)])) - cert = ( + builder = ( x509.CertificateBuilder() - .subject_name(name).issuer_name(name) + .subject_name(subject) + .issuer_name(issuer) .public_key(priv.public_key()) - .serial_number(x509.random_serial_number()) - .not_valid_before(datetime.utcnow() - timedelta(minutes=5)) - .not_valid_after(datetime.utcnow() + timedelta(days=365)) - # ---- LEAF EXTENSIONS – **none** of them critical ------------------- - # .add_extension( - # x509.BasicConstraints(ca=False, path_length=None), critical=False - # ) - # .add_extension( - # x509.KeyUsage( - # digital_signature=True, - # key_encipherment=False, - # content_commitment=False, - # data_encipherment=False, - # key_agreement=False, - # key_cert_sign=False, - # crl_sign=False, - # encipher_only=False, - # decipher_only=False, - # ), - # critical=False, - # ) - # .add_extension( - # x509.ExtendedKeyUsage([EKU.SERVER_AUTH]), critical=False - # ) - .add_extension( - x509.SubjectAlternativeName(sans), critical=False - ) - .sign(priv, algorithm=None) + .serial_number(serial_numer) + .not_valid_before(not_valid_before) + .not_valid_after(not_valid_after) + .add_extension(x509.SubjectAlternativeName( + x509.GeneralNames(ext)), critical=False) ) + cert = builder.sign(private_key=priv, algorithm=None) # Note: Ed25519 = algorithm None + + #der_bytes = cert.public_bytes(serialization.Encoding.DER) + #pem_bytes = cert.public_bytes(serialization.Encoding.PEM) + # with open("clone2.pem", "wb") as f: + # f.write(pem_bytes) + return ( priv.private_bytes( serialization.Encoding.PEM, @@ -66,3 +132,18 @@ def write_cert(pk_pem, pk_file, cert_pem, cert_file): with open(cert_file, 'wb') as f: f.write(cert_pem) + + +def read_cert_public_key(cert_file: str) -> bytes: + with open(cert_file, "rb") as f: + cert_pem = f.read() + + cert = x509.load_pem_x509_certificate(cert_pem) + public_key = cert.public_key() + try: + return public_key.public_bytes_raw() + except AttributeError: + return public_key.public_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PublicFormat.Raw, + ) diff --git a/pyjamaz/transport/jamnp_s/__init__.py b/pyjamaz/transport/jamnp_s/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pyjamaz/transport/jamnp_s/connection.py b/pyjamaz/transport/jamnp_s/connection.py new file mode 100644 index 00000000..d76e9929 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/connection.py @@ -0,0 +1,192 @@ +import asyncio +import logging +from enum import Enum + +from cryptography.hazmat.primitives import serialization + +from aioquic.asyncio import QuicConnectionProtocol +from aioquic.quic.events import ( + ConnectionTerminated, + HandshakeCompleted, + QuicEvent, + StreamDataReceived, + StreamReset, +) + +from pyjamaz.transport.jamnp_s.types import JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class JAMConnectionDirection(Enum): + initiator: int = 0 + acceptor: int = 1 + + +class JAMConnection(QuicConnectionProtocol): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Note: is set in wrap_protocol call + self.direction:JAMConnectionDirection = None + self.protocol = None + self.stream_manager = None + self.jam_connection_ulid = None + self.host = None + self.port = None + self.addr = None + self.validator_key = None + + self.stream_up = None + self.streams = {} #TODO: typings + self._keepalive_task = asyncio.create_task(self.keepalive()) + + + def close_stream(self, stream_id: int, clean_close: bool = True, reason: int = 0): + logger.debug( + f"Connection {self.jam_connection_ulid} QUIC closing stream {stream_id} (clean: {clean_close})" + ) + + if clean_close: + self.send(stream_id, b"", end_stream=True) + return + + self.reset_stream(stream_id, reason) + + + def reset_stream(self, stream_id: int, error_code: int): + logger.debug( + f"Connection {self.jam_connection_ulid} QUIC resetting stream {stream_id} with code {error_code}" + ) + self._quic.reset_stream(stream_id, error_code=error_code) + self.transmit() + + + def is_connected(self) -> bool: + """Check if the connection is active and ready""" + return ( + self._quic is not None + and not self._quic._close_pending + and self.stream_up is not None + and not self.stream_up.closed + ) + + + def send(self, stream_id: int, data: bytes, end_stream=False): + try: + self._quic.send_stream_data( + stream_id, + data, + end_stream=end_stream + ) + self.transmit() + except Exception as e: + #TODO!!!!!!!!!!!!!!!!!! + logger.error(f"Connection {self.jam_connection_ulid} error") + logger.error(e) + raise + + + # def connection_made(self, transport): + # Note: initiator does not seem to have its connection info available here + # super().connection_made(transport) + # self.host, self.port = transport._extra["sockname"][0:2] + # self.addr = f"{self.host}:{self.port}" + + + def connection_lost(self, exc): + logger.debug(f"Connection {self.jam_connection_ulid} QUIC UDP transport closed") + self._keepalive_task.cancel() + if self.protocol is not None: + self.protocol.disconnect(self) + super().connection_lost(exc) + + + async def keepalive(self): + try: + while True: + #TODO: what is a sane amount of time? Usefull for detecting disconnect (early)? + await asyncio.sleep(3) + self._quic.send_ping(id(self)) + self.transmit() + except asyncio.CancelledError: + pass + + + def get_peer_validator_key(self) -> bytes | None: + peer_certificate = getattr(self._quic.tls, "_peer_certificate", None) + if peer_certificate is None: + return None + + public_key = peer_certificate.public_key() + try: + return public_key.public_bytes_raw() + except AttributeError: + return public_key.public_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PublicFormat.Raw, + ) + + + def quic_event_received(self, event: QuicEvent) -> None: + if event and hasattr(event, "stream_id"): + if event.stream_id != 0: + logger.debug(f'Connection {self.jam_connection_ulid} stream {event.stream_id} received data {event}') + else: + logger.debug(f'Connection {self.jam_connection_ulid} QUIC received non stream data {event}') + + if isinstance(event, HandshakeCompleted): + #TODO: enforce: + # Both nodes are validators, and are neighbours in the grid structure. + # Or at least one of the nodes is not a validator. + + peer_validator_key = self.get_peer_validator_key() + if peer_validator_key is not None: + if self.validator_key is not None and peer_validator_key != self.validator_key: + logger.warning( + "Connection %s peer certificate key mismatch: expected %s got %s", + self.jam_connection_ulid, + self.validator_key.hex(), + peer_validator_key.hex(), + ) + self.close(error_code=2, reason_phrase="validator key mismatch") + return + + if self.protocol.validator_manager.has_tracked_validator(peer_validator_key): + self.protocol.validator_manager.bind_connection(peer_validator_key, self) + + if self.direction == JAMConnectionDirection.initiator: + addr = f"{self.host}:{self.port}" + if not self.protocol.peer_registry.activate(self, addr): + return + + # Initiating side will send a JAM handshake message and set the stream id + stream_up = self.stream_manager.open_outgoing(self, JAMStreamKind.UP0_BlockAnnouncement) + self.stream_up = stream_up + self.protocol.handler(JAMStreamKind.UP0_BlockAnnouncement).send_handshake(self) + else: + # Note: it seems only now we have this info available from the accepting side (aioquick quirk) + self.host, self.port = self._quic._network_paths[0].addr[0:2] + addr = f"{self.host}:{self.port}" + if not self.protocol.peer_registry.activate(self, addr): + return + + elif isinstance(event, StreamReset): + self.stream_manager.receive_reset(self, event.stream_id, event.error_code) + + elif isinstance(event, StreamDataReceived): + stream_id = event.stream_id + data = bytes(event.data) + + logger.debug(f"Connection {self.jam_connection_ulid} StreamDataReceived: stream_id={stream_id}, data_len={len(data)}, end_stream={event.end_stream}") + + try: + self.stream_manager.receive_stream_data(self, stream_id, data, event.end_stream) + except Exception as e: + logger.error(f"Connection {self.jam_connection_ulid} Error handling stream data: {e}", exc_info=True) + raise + + elif isinstance(event, ConnectionTerminated): + logger.debug(f"Connection {self.jam_connection_ulid} QUIC connection terminated with code {event.error_code}") + self.protocol.disconnect(self) diff --git a/pyjamaz/transport/jamnp_s/network.py b/pyjamaz/transport/jamnp_s/network.py new file mode 100644 index 00000000..7797ecb5 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/network.py @@ -0,0 +1,258 @@ +from __future__ import annotations + +import asyncio +import logging +import ssl +from typing import Optional, cast + +from ulid import ULID + +from aioquic.asyncio import serve +from aioquic.asyncio.client import connect +from aioquic.quic.configuration import QuicConfiguration +from aioquic.quic.connection import QuicConnection + +from pyjamaz.constants import MESSAGE_TYPES +from pyjamaz.transport.jamnp_s.connection import JAMConnection, JAMConnectionDirection +from pyjamaz.transport.jamnp_s.peers import PeerRegistry +from pyjamaz.transport.jamnp_s.stream_manager import StreamManager +from pyjamaz.transport.jamnp_s.protocol import ProtocolContext, ProtocolSharedState, register_handlers +from pyjamaz.transport.jamnp_s.types import JAMStreamKind +from pyjamaz.transport.jamnp_s.validator_manager import ValidatorConnectionManager +from pyjamaz.transport.types import ProtocolType + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + +""" +Note: Monkeypatch :S + +we monkeypatch aioquic.quic.connection.QuicConnection._initialize +after aioquic creates its internal TLS context, it sets self.tls._request_client_certificate = True +that makes the server send a TLS CertificateRequest, so the client includes its certificate during the handshake +pyjamaz/transport/jamnp_s/connection.py reads the peer certificate on HandshakeCompleted to derive the remote validator key and bind the connection + +As of aioquic is 1.2.0 + - QuicConfiguration has no public request_client_certificate option in aioquic/quic/configuration.py + - aioquic TLS context keeps _request_client_certificate = False by default, explicitly marked "for test purposes only" in aioquic/tls.py:1276 + - the server only emits CertificateRequest when that private flag is true in aioquic/tls.py:2036 +""" +if QuicConnection is not None and not getattr(QuicConnection, "_pyjamaz_client_cert_patch", False): + _original_initialize = QuicConnection._initialize + + def _initialize_with_client_certificate(self, peer_cid: bytes) -> None: + _original_initialize(self, peer_cid) + self.tls._request_client_certificate = True + + QuicConnection._initialize = _initialize_with_client_certificate + QuicConnection._pyjamaz_client_cert_patch = True + + +def quick_client_config(protocol_name: str, certificate: str, private_key: str) -> QuicConfiguration: + configuration = QuicConfiguration( + alpn_protocols=[protocol_name], + is_client=True, + verify_mode=ssl.CERT_NONE, + ) + configuration.load_cert_chain(certfile=certificate, keyfile=private_key) + return configuration + + +def quick_server_config(protocol_name: str, certificate: str, private_key: str) -> QuicConfiguration: + configuration = QuicConfiguration( + alpn_protocols=[protocol_name], + is_client=False, + ) + configuration.load_cert_chain(certificate, private_key) + return configuration + + +def _create_jam_connection( + network: "JAMNPS", + direction: JAMConnectionDirection, + host: str, + port: int, + validator_key: Optional[bytes], +): + def create_connection(*args, **kwargs): + conn = JAMConnection(*args, **kwargs) + conn.protocol = network + conn.direction = direction + conn.stream_manager = network.stream_manager + conn.jam_connection_ulid = ULID() + conn.validator_key = validator_key + + if direction == JAMConnectionDirection.initiator: + conn.host = host + conn.port = port + + network.peer_registry.register(conn) + if validator_key is not None: + network.validator_manager.bind_connection(validator_key, conn) + + return conn + + return create_connection + + +class JAMNPS(ProtocolType): + MAX_MESSAGE_SIZE = 10000000 + PROTOCOL_NAME = "jamnp-s/0/{}" + VALIDATOR_CHECK_INTERVAL = 3.0 + + def __init__(self, host, port, certificate, private_key, app): + self.host = host + self.port = port + self.pubsub = app.pubsub + self.app = app + self.cert = certificate + self.pk = private_key + + bl_hash = app.retrieve_block_hash(0).hex() + if bl_hash.startswith("0x"): + bl_hash = bl_hash[2:] + bl_hash = bl_hash[:8] + + self.protocol_name = JAMNPS.PROTOCOL_NAME.format(bl_hash) + self.configuration = quick_client_config(self.protocol_name, certificate, private_key) + self.conn_out = None + self.connection_tasks: dict[str, asyncio.Task[None]] = {} + + self.peer_registry = PeerRegistry(self) + self.stream_manager = StreamManager(self.MAX_MESSAGE_SIZE) + self.validator_manager = ValidatorConnectionManager( + app=self.app, + connect_callback=self.connect, + disconnect_callback=self.disconnect, + port_override=self.port, + ) + self.context = ProtocolContext( + app=self.app, + peer_registry=self.peer_registry, + validator_manager=self.validator_manager, + stream_manager=self.stream_manager, + state=ProtocolSharedState(), + ) + self.protocol_handlers = register_handlers(self.stream_manager, self.context) + + #TODO: add all handlers + up0_handler = self.handler(JAMStreamKind.UP0_BlockAnnouncement) + ce128_handler = self.handler(JAMStreamKind.CE128_BlockRequest) + ce131_handler = self.handler(JAMStreamKind.CE131_SafroleTicketDistributionStep1) + + self.pubsub.subscribe(MESSAGE_TYPES.PRODUCED_BLOCK, up0_handler.broadcast_block) + self.pubsub.subscribe(MESSAGE_TYPES.CE128_SUCCESS, ce128_handler.finish_block_request) + self.pubsub.subscribe(MESSAGE_TYPES.CE128_FAILURE, ce128_handler.finish_block_request) + self.pubsub.subscribe(MESSAGE_TYPES.TICKET_ADD, ce131_handler.broadcast_own_ticket) + + + @property + def validator(self): + return self.validator_manager.validator + + + @property + def validator_dns(self): + return self.validator_manager.validator_dns + + + @property + def validator_port(self): + return self.validator_manager.validator_port + + + @property + def validator_address(self): + return self.validator_manager.validator_address + + + def handler(self, kind: JAMStreamKind): + return self.protocol_handlers[kind] + + + async def listen(self): + logger.info(f"Listening on {self.host}:{self.port}") + + server_conf = quick_server_config(self.protocol_name, self.cert, self.pk) + await serve( + self.host, + self.port, + configuration=server_conf, + create_protocol=_create_jam_connection( + self, + JAMConnectionDirection.acceptor, + self.host, + self.port, + None, + ), + retry=True, + ) + + + def should_initiate_connection(self, validator_a: bytes, validator_b: bytes) -> bool: + return self.validator_manager.should_initiate_connection(validator_a, validator_b) + + + async def update_connections(self): + await self.validator_manager.update_validator_connections() + + + async def connect(self, host: str, port: int, validator_key: Optional[bytes]): + addr = f"{host}:{port}" + if addr in self.peer_registry.conn_addr: + logger.warning(f"Ignoring duplicate connection to {addr}") + return + + if addr in self.connection_tasks: + logger.debug(f"Connection attempt already in progress for {addr}") + return + + task = asyncio.create_task(self.connect_task(host, port, validator_key)) + self.connection_tasks[addr] = task + + def _cleanup(finished: asyncio.Task[None]) -> None: + self.connection_tasks.pop(addr, None) + try: + finished.result() + except Exception as exc: + logger.warning(f"💩 Connection task for {addr} failed: {exc}") + + task.add_done_callback(_cleanup) + + + async def connect_task(self, host: str, port: int, validator_key: Optional[bytes]) -> None: + configuration = quick_client_config(self.protocol_name, self.cert, self.pk) + + logger.info(f"Connecting to {host}:{port}") + try: + async with connect( + host, + port, + configuration=configuration, + create_protocol=_create_jam_connection( + self, + JAMConnectionDirection.initiator, + host, + port, + validator_key, + ), + ) as client: + client = cast(JAMConnection, client) + await client.wait_closed() + self.disconnect(client) + except ConnectionError as exc: + logger.warning(f"💩 Cannot connect to {host}:{port} {exc}") + + + async def check_connections(self) -> None: + while True: + try: + await self.update_connections() + except Exception as exc: + logger.warning(f"Validator connectivity maintenance failed: {exc}") + await asyncio.sleep(self.VALIDATOR_CHECK_INTERVAL) + + + def disconnect(self, connection: JAMConnection, validator_key: Optional[bytes] = None): + self.stream_manager.cleanup_connection(connection) + self.peer_registry.unregister(connection) + self.validator_manager.on_disconnect(connection, validator_key) diff --git a/pyjamaz/transport/jamnp_s/peers.py b/pyjamaz/transport/jamnp_s/peers.py new file mode 100644 index 00000000..22eff046 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/peers.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +import logging +from typing import TYPE_CHECKING + +from pyjamaz.transport.jamnp_s.connection import JAMConnectionDirection + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + +if TYPE_CHECKING: + from pyjamaz.transport.jamnp_s.connection import JAMConnection + from pyjamaz.transport.jamnp_s.network import JAMNPS + + +class PeerRegistry: + def __init__(self, protocol: "JAMNPS") -> None: + self.protocol = protocol + self.connections = {} + self.conn_accepted = set() + self.conn_initiated = set() + self.conn_addr = set() + + + def register(self, connection: "JAMConnection") -> None: + self.connections[connection.jam_connection_ulid] = connection + if connection.direction == JAMConnectionDirection.initiator: + self.conn_initiated.add(connection.jam_connection_ulid) + else: + self.conn_accepted.add(connection.jam_connection_ulid) + + + def activate(self, connection: "JAMConnection", addr: str) -> bool: + if addr in self.conn_addr and connection.addr != addr: + logger.warning( + f"Duplicate connection from {connection.jam_connection_ulid} direction: {connection.direction} : {addr}" + ) + connection.close(error_code=2, reason_phrase="duplicate") + self.unregister(connection) + return False + + connection.addr = addr + self.conn_addr.add(addr) + + if ( + connection.direction == JAMConnectionDirection.initiator + and self.protocol.conn_out is None + ): + self.protocol.conn_out = connection + + logger.debug( + f"Connection {connection.jam_connection_ulid} direction: {connection.direction} added {connection.addr}" + ) + return True + + + def unregister(self, connection: "JAMConnection") -> None: + self.conn_initiated.discard(connection.jam_connection_ulid) + self.conn_accepted.discard(connection.jam_connection_ulid) + self.connections.pop(connection.jam_connection_ulid, None) + + if connection.addr: + self.conn_addr.discard(connection.addr) + + if self.protocol.conn_out is connection: + self.protocol.conn_out = next( + ( + conn + for conn in self.connections.values() + if conn.direction == JAMConnectionDirection.initiator and conn.addr is not None + ), + None, + ) diff --git a/pyjamaz/transport/jamnp_s/protocol/__init__.py b/pyjamaz/transport/jamnp_s/protocol/__init__.py new file mode 100644 index 00000000..c0c57398 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/__init__.py @@ -0,0 +1,55 @@ +from pyjamaz.transport.jamnp_s.protocol.context import ProtocolContext, ProtocolSharedState + + +def register_handlers(stream_manager, context: ProtocolContext): + from pyjamaz.transport.jamnp_s.protocol.ce128 import CE128Handler + from pyjamaz.transport.jamnp_s.protocol.ce129 import CE129Handler + from pyjamaz.transport.jamnp_s.protocol.ce131 import CE131Handler + from pyjamaz.transport.jamnp_s.protocol.ce132 import CE132Handler + from pyjamaz.transport.jamnp_s.protocol.ce133 import CE133Handler + from pyjamaz.transport.jamnp_s.protocol.ce134 import CE134Handler + from pyjamaz.transport.jamnp_s.protocol.ce135 import CE135Handler + from pyjamaz.transport.jamnp_s.protocol.ce136 import CE136Handler + from pyjamaz.transport.jamnp_s.protocol.ce137 import CE137Handler + from pyjamaz.transport.jamnp_s.protocol.ce138 import CE138Handler + from pyjamaz.transport.jamnp_s.protocol.ce139 import CE139Handler + from pyjamaz.transport.jamnp_s.protocol.ce140 import CE140Handler + from pyjamaz.transport.jamnp_s.protocol.ce141 import CE141Handler + from pyjamaz.transport.jamnp_s.protocol.ce142 import CE142Handler + from pyjamaz.transport.jamnp_s.protocol.ce143 import CE143Handler + from pyjamaz.transport.jamnp_s.protocol.ce144 import CE144Handler + from pyjamaz.transport.jamnp_s.protocol.ce145 import CE145Handler + from pyjamaz.transport.jamnp_s.protocol.up0 import UP0Handler + + handlers = [ + UP0Handler(context), + CE128Handler(context), + CE129Handler(context), + CE131Handler(context), + CE132Handler(context), + CE133Handler(context), + CE134Handler(context), + CE135Handler(context), + CE136Handler(context), + CE137Handler(context), + CE138Handler(context), + CE139Handler(context), + CE140Handler(context), + CE141Handler(context), + CE142Handler(context), + CE143Handler(context), + CE144Handler(context), + CE145Handler(context), + ] + + for handler in handlers: + context.register_handler(handler) + stream_manager.register_handler(handler) + return context.handlers + + +__all__ = [ + "ProtocolContext", + "ProtocolSharedState", + "register_handlers", +] diff --git a/pyjamaz/transport/jamnp_s/protocol/base.py b/pyjamaz/transport/jamnp_s/protocol/base.py new file mode 100644 index 00000000..4dd3c1a3 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/base.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from pyjamaz.transport.jamnp_s.types import IStreamHandler, JAMStream, StreamDirection + +if TYPE_CHECKING: + from pyjamaz.transport.jamnp_s.connection import JAMConnection + from pyjamaz.transport.jamnp_s.protocol.context import ProtocolContext + from pyjamaz.transport.jamnp_s.types import JAMStreamKind + + +class StreamHandler(IStreamHandler): + kind: "JAMStreamKind" + + def __init__(self, context: "ProtocolContext") -> None: + self.context = context + + def init_stream(self, stream: JAMStream) -> None: + pass + + def on_message(self, stream: JAMStream, data: bytes) -> None: + if stream.direction == StreamDirection.initiator: + self.initiator_message(stream, data) + else: + self.acceptor_message(stream, data) + + def on_fin(self, stream: JAMStream) -> None: + if stream.direction == StreamDirection.initiator: + self.initiator_fin(stream) + else: + self.acceptor_fin(stream) + + def on_reset(self, stream: JAMStream, reset_code: int) -> None: + if stream.direction == StreamDirection.initiator: + self.initiator_reset(stream, reset_code) + else: + self.acceptor_reset(stream, reset_code) + + def on_close(self, stream: JAMStream) -> None: + pass + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + raise NotImplementedError + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + raise NotImplementedError + + def initiator_fin(self, stream: JAMStream) -> None: + pass + + def acceptor_fin(self, stream: JAMStream) -> None: + pass + + def initiator_reset(self, stream: JAMStream, reset_code: int) -> None: + pass + + def acceptor_reset(self, stream: JAMStream, reset_code: int) -> None: + pass + + def open_outgoing(self, conn: "JAMConnection") -> JAMStream: + return self.context.stream_manager.open_outgoing(conn, self.kind) diff --git a/pyjamaz/transport/jamnp_s/protocol/ce128.py b/pyjamaz/transport/jamnp_s/protocol/ce128.py new file mode 100644 index 00000000..f8009d56 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce128.py @@ -0,0 +1,145 @@ +from __future__ import annotations + +import asyncio +import logging +from dataclasses import dataclass +from typing import List + +from jamcodec.base import JamBytes + +from pyjamaz.constants import MESSAGE_TYPES +from pyjamaz.models.block import Block, Header +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce128 import ( + MsgCE128BlockRequest, + MsgCE128BlockRequestDirection, + MsgCE128BlockRequestResponse, +) +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +@dataclass +class CE128StreamState: + active: bool = True + + +class CE128Handler(StreamHandler): + kind = JAMStreamKind.CE128_BlockRequest + + def __init__(self, context) -> None: + super().__init__(context) + self._streams = {} + + def init_stream(self, stream: JAMStream) -> None: + self._streams[stream.stream_key] = CE128StreamState() + + def initiate_block_request(self, conn, req: MsgCE128BlockRequest) -> JAMStream: + stream = self.open_outgoing(conn) + logger.info( + f"Initiate block request on stream id: {stream.stream_id} direction: {req.direction}, " + f"max_block: {req.max_blocks} header hash: {req.header_hash}" + ) + conn.send( + stream.stream_id, + stream.create_message(req.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + async def finish_block_request(self, *args, **kwargs) -> None: + self.context.state_requesting_blocks = False + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug( + f"CE128 initiated stream {stream.stream_id} received block request response: {len(data)} bytes" + ) + req = MsgCE128BlockRequestResponse.from_jam_bytes(JamBytes(data)) + blocks = req.blocks + logger.info(f"Parsed {len(blocks)} blocks") + # asyncio.create_task( + # self.context.app.import_queue_add_blocks( + # blocks, + # on_success=MESSAGE_TYPES.CE128_SUCCESS, + # on_failure=MESSAGE_TYPES.CE128_FAILURE, + # ) + # ) + for block in blocks: + asyncio.create_task( + self.context.app.runtime.accumulate_pipeline.add_block(block) + ) + + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug(f"CE128 acceptor stream {stream.stream_id} received block request") + self._send_block_request_response( + stream, + MsgCE128BlockRequest.from_jam_bytes(JamBytes(data)), + ) + + def initiator_fin(self, stream: JAMStream) -> None: + self._abort_block_request() + + def acceptor_fin(self, stream: JAMStream) -> None: + self._abort_block_request() + + def initiator_reset(self, stream: JAMStream, reset_code: int) -> None: + asyncio.create_task(self.finish_block_request(reset_code)) + + def acceptor_reset(self, stream: JAMStream, reset_code: int) -> None: + asyncio.create_task(self.finish_block_request(reset_code)) + + def on_close(self, stream: JAMStream) -> None: + self._streams.pop(stream.stream_key, None) + + def _send_block_request_response(self, stream: JAMStream, block_req: MsgCE128BlockRequest) -> None: + block: Block = None + blocks: List[Block] = [] + last_block_hash = self.context.app.retrieve_block_hash(self.context.app.working_state.timeslot.number) + block_header: Header = self.context.app.retrieve_block_header(block_req.header_hash) + next_hash = block_req.header_hash + + if block_header and block_req.max_blocks > 0: + for _ in range(block_req.max_blocks): + if block_req.direction == MsgCE128BlockRequestDirection.ASC.value: + block_child_hash: bytes = self.context.app.retrieve_block_child_hash(next_hash) + if block_child_hash: + block = self.context.app.retrieve_block_by_hash(block_child_hash) + next_hash = block.header.hash + else: + break + elif block_req.direction == MsgCE128BlockRequestDirection.DESC.value: + block = self.context.app.retrieve_block_by_hash(next_hash) + if not block or block.header.timeslot == 0 or block.header.hash == bytes(32): + break + next_hash = block.header.parent + else: + raise RuntimeError("Unsupported CE128 block request direction") + + blocks.append(block) + + if blocks: + logger.info( + f"Send {len(blocks)} blocks (direction={block_req.direction} max blocks={block_req.max_blocks})" + ) + stream.conn.send( + stream.stream_id, + stream.create_message(MsgCE128BlockRequestResponse(blocks=blocks).to_jam_bytes().to_bytes()), + end_stream=True, + ) + return + + logger.info( + f"No blocks to send requested: {block_req.header_hash.hex()} current: {last_block_hash.hex()}" + ) + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def _abort_block_request(self) -> None: + logger.info(f"Finished, start parsing import queue {len(self.context.app.import_queue)}") + asyncio.create_task( + self.context.app.process_import_queue( + on_success=MESSAGE_TYPES.CE128_SUCCESS, + on_failure=MESSAGE_TYPES.CE128_FAILURE, + ) + ) diff --git a/pyjamaz/transport/jamnp_s/protocol/ce129.py b/pyjamaz/transport/jamnp_s/protocol/ce129.py new file mode 100644 index 00000000..51408821 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce129.py @@ -0,0 +1,14 @@ +from __future__ import annotations + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + + +class CE129Handler(StreamHandler): + kind = JAMStreamKind.CE129_StateRequest + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + pass + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + pass diff --git a/pyjamaz/transport/jamnp_s/protocol/ce131.py b/pyjamaz/transport/jamnp_s/protocol/ce131.py new file mode 100644 index 00000000..7b4f3798 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce131.py @@ -0,0 +1,119 @@ +from __future__ import annotations + +import asyncio +import logging +from dataclasses import dataclass + +from jamcodec.base import JamBytes + +from pyjamaz.graypaper_constants import EPOCH_TIMESLOTS +from pyjamaz.models.block import TicketEnvelope +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce131 import ( + MsgCE131SafroleTicket, + MsgCE131SafroleTicketDistribution, +) +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +@dataclass +class CE131StreamState: + active: bool = True + + +class CE131Handler(StreamHandler): + kind = JAMStreamKind.CE131_SafroleTicketDistributionStep1 + + def __init__(self, context) -> None: + super().__init__(context) + self._streams = {} + + def init_stream(self, stream: JAMStream) -> None: + self._streams[stream.stream_key] = CE131StreamState() + + async def broadcast_own_ticket(self, data) -> int: + epoch_index, attempt, proof = data + msg = MsgCE131SafroleTicketDistribution( + epoch_index=epoch_index, + ticket=MsgCE131SafroleTicket(attempt=attempt, proof=proof), + ) + + distributed_count = 0 + for conn in self.context.connections.values(): + if not conn.is_connected(): + continue + + try: + stream = self.open_outgoing(conn) + logger.info(f"Send ticker announcement on stream id: {stream.stream_id} to {conn.host}:{conn.port}") + conn.send( + stream.stream_id, + stream.create_message(msg.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + distributed_count += 1 + except Exception as exc: + logger.error(f"Failed to distribute ticket to peer {conn.host}:{conn.port}: {exc}") + + logger.info(f"Distributed ticket to {distributed_count} peers") + return distributed_count + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.warning(f"Unexpected data in CE131 initiator: {len(data)} bytes") + raise ValueError("Unexpected data in CE131 initiator") + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug(f"CE131 acceptor stream {stream.stream_id} received ticket") + self._handle_received_ticket( + stream, + MsgCE131SafroleTicketDistribution.from_jam_bytes(JamBytes(data)), + ) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.info("Finished with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.info("Finished with FIN") + + def on_close(self, stream: JAMStream) -> None: + self._streams.pop(stream.stream_key, None) + + def _handle_received_ticket(self, stream: JAMStream, msg: MsgCE131SafroleTicketDistribution) -> None: + logger.info(f"Received ticket for epoch {msg.epoch_index}") + + current_epoch = self.context.app.working_state.timeslot.number // EPOCH_TIMESLOTS + if msg.epoch_index < current_epoch: + logger.warning(f"Invalid epoch index {msg.epoch_index}, current epoch is {current_epoch}") + stream.send_reset(1) + return + + try: + ring_public_keys = [v.bandersnatch for v in self.context.app.working_state.safrole.validators] + entropy = self.context.app.working_state.entropy.entropy[2] + ticket_envelope = TicketEnvelope(attempt=msg.ticket.attempt, signature=msg.ticket.proof) + ticket_body = self.context.app.block_extrinsic.create_ticket_body( + ticket_envelope, + ring_public_keys, + entropy, + ) + + if ticket_body in self.context.app.working_state.safrole.ticket_accumulator: + logger.info("Ticket already in accumulator") + stream.send_reset(2) + return + + asyncio.create_task( + self.context.app.block_extrinsic.add_ticket_body( + ticket_envelope, + ticket_body, + ) + ) + logger.info(f"Ticket added for epoch {msg.epoch_index}") + except ValueError as exc: + logger.error(f"Invalid ticket: {exc}") + stream.send_reset(3) + return + + stream.conn.send(stream.stream_id, b"", end_stream=True) diff --git a/pyjamaz/transport/jamnp_s/protocol/ce132.py b/pyjamaz/transport/jamnp_s/protocol/ce132.py new file mode 100644 index 00000000..3e459d6e --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce132.py @@ -0,0 +1,105 @@ +from __future__ import annotations + +import asyncio +import logging +from dataclasses import dataclass + +from jamcodec.base import JamBytes + +from pyjamaz.graypaper_constants import EPOCH_TIMESLOTS +from pyjamaz.models.block import TicketEnvelope +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce132 import MsgCE132SafroleTicketDistribution +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +@dataclass +class CE132StreamState: + active: bool = True + + +class CE132Handler(StreamHandler): + kind = JAMStreamKind.CE132_SafroleTicketDistributionStep2 + + def __init__(self, context) -> None: + super().__init__(context) + self._streams = {} + + def init_stream(self, stream: JAMStream) -> None: + self._streams[stream.stream_key] = CE132StreamState() + + def initiate_ticket_distribution(self, conn, msg: MsgCE132SafroleTicketDistribution) -> JAMStream: + stream = self.open_outgoing(conn) + logger.info(f"Distribute ticket on stream id: {stream.stream_id} to {conn.host}:{conn.port}") + conn.send( + stream.stream_id, + stream.create_message(msg.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.warning(f"Unexpected data in CE132 initiator: {len(data)} bytes") + raise ValueError("Unexpected data in CE132 initiator") + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug(f"CE132 acceptor stream {stream.stream_id} received ticket") + self._handle_received_ticket( + stream, + MsgCE132SafroleTicketDistribution.from_jam_bytes(JamBytes(data)), + ) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.debug("Success with code 0") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.debug("Success with code 0") + + def initiator_reset(self, stream: JAMStream, reset_code: int) -> None: + logger.error(f"Failed with code {reset_code}") + + def acceptor_reset(self, stream: JAMStream, reset_code: int) -> None: + logger.error(f"Failed with code {reset_code}") + + def on_close(self, stream: JAMStream) -> None: + self._streams.pop(stream.stream_key, None) + + def _handle_received_ticket(self, stream: JAMStream, msg: MsgCE132SafroleTicketDistribution) -> None: + logger.info(f"Received ticket for epoch {msg.epoch_index}") + + current_epoch = self.context.app.working_state.timeslot.number // EPOCH_TIMESLOTS + if msg.epoch_index < current_epoch: + logger.warning(f"Invalid epoch index {msg.epoch_index}, current epoch is {current_epoch}") + stream.send_reset(1) + return + + try: + ring_public_keys = [v.bandersnatch for v in self.context.app.working_state.safrole.validators] + entropy = self.context.app.working_state.entropy.entropy[2] + ticket_envelope = TicketEnvelope(attempt=msg.ticket.attempt, signature=msg.ticket.proof) + ticket_body = self.context.app.block_extrinsic.create_ticket_body( + ticket_envelope, + ring_public_keys, + entropy, + ) + + if ticket_body in self.context.app.working_state.safrole.ticket_accumulator: + logger.info("Ticket already in accumulator (via CE132), ignoring") + stream.conn.send(stream.stream_id, b"", end_stream=True) + return + + asyncio.create_task( + self.context.app.block_extrinsic.add_ticket_body( + ticket_envelope, + ticket_body, + ) + ) + logger.info(f"Valid ticket received via CE132 (forwarded) for epoch {msg.epoch_index}") + except ValueError as exc: + logger.error(f"Invalid ticket: {exc}") + stream.send_reset(3) + return + + stream.conn.send(stream.stream_id, b"", end_stream=True) diff --git a/pyjamaz/transport/jamnp_s/protocol/ce133.py b/pyjamaz/transport/jamnp_s/protocol/ce133.py new file mode 100644 index 00000000..83468a21 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce133.py @@ -0,0 +1,96 @@ +from __future__ import annotations + +import logging +from dataclasses import dataclass +from typing import List, Optional + +from jamcodec.base import JamBytes + +from pyjamaz.hashing import blake2b_256_hash +from pyjamaz.models.common import WorkPackage +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce133 import ( + MsgCE133Extrinsic, + MsgCE133WorkPackageSubmission, +) +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +@dataclass +class CE133StreamState: + work_package: Optional[WorkPackage] = None + + +class CE133Handler(StreamHandler): + kind = JAMStreamKind.CE133_WorkPackageSubmission + + def __init__(self, context) -> None: + super().__init__(context) + self._streams = {} + + def init_stream(self, stream: JAMStream) -> None: + self._streams[stream.stream_key] = CE133StreamState() + + def initiate_workpackage_submission( + self, + conn, + wp: MsgCE133WorkPackageSubmission, + extrinsic: MsgCE133Extrinsic, + ) -> JAMStream: + stream = self.open_outgoing(conn) + logger.info(f"Initiating workpackage submission on stream id: {stream.stream_id}") + conn.send( + stream.stream_id, + stream.create_message(wp.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=False, + ) + conn.send( + stream.stream_id, + stream.create_message(extrinsic.to_jam_bytes().to_bytes()), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.warning(f"Unexpected data in CE133 initiator: {len(data)} bytes") + raise ValueError("Unexpected data in CE133 initiator") + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + state = self._streams[stream.stream_key] + + if state.work_package is None: + logger.debug("CE133 acceptor received work package") + msg = MsgCE133WorkPackageSubmission.from_jam_bytes(JamBytes(data)) + state.work_package = msg.work_package + return + + logger.debug("CE133 acceptor received extrinsic data") + extrinsics_list: List[bytes] = [] + extrinsics_data = JamBytes(data) + + for item in state.work_package.items: + for ext in item.extrinsic: + ext_data = extrinsics_data.get_next_bytes(ext.len) + if blake2b_256_hash(ext_data) != ext.hash: + raise ValueError("Extrinsic hash mismatch") + extrinsics_list.append(ext_data) + + stream.conn.send(stream.stream_id, b"", end_stream=True) + self.context.app.add_work_package(state.work_package, extrinsics_list) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.debug("CE133 submission successful with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.debug("CE133 submission successful with FIN") + + def initiator_reset(self, stream: JAMStream, reset_code: int) -> None: + logger.debug(f"CE133 received reset code: {reset_code}") + + def acceptor_reset(self, stream: JAMStream, reset_code: int) -> None: + logger.debug(f"CE133 received reset code: {reset_code}") + + def on_close(self, stream: JAMStream) -> None: + self._streams.pop(stream.stream_key, None) diff --git a/pyjamaz/transport/jamnp_s/protocol/ce134.py b/pyjamaz/transport/jamnp_s/protocol/ce134.py new file mode 100644 index 00000000..84c834fc --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce134.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +import logging +from dataclasses import dataclass +from typing import Optional + +from jamcodec.base import JamBytes + +from pyjamaz.models.common import WorkPackage +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce134 import ( + MsgCE134RefineResponse, + MsgCE134WorkPackageBundle, + MsgCE134WorkPackageSharing, +) +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +@dataclass +class CE134StreamState: + received_mappings: bool = False + sharing_msg: Optional[MsgCE134WorkPackageSharing] = None + + +class CE134Handler(StreamHandler): + kind = JAMStreamKind.CE134_WorkPackageSharing + + def __init__(self, context) -> None: + super().__init__(context) + self._streams = {} + + def init_stream(self, stream: JAMStream) -> None: + self._streams[stream.stream_key] = CE134StreamState() + + def initiate_workpackage_sharing( + self, + conn, + sharing: MsgCE134WorkPackageSharing, + bundle: MsgCE134WorkPackageBundle, + ) -> JAMStream: + stream = self.open_outgoing(conn) + logger.info(f"Initiate sharing workpage on stream id: {stream.stream_id} to {conn.host}:{conn.port}") + conn.send( + stream.stream_id, + stream.create_message(sharing.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=False, + ) + conn.send( + stream.stream_id, + stream.create_message(bundle.to_jam_bytes().to_bytes()), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + state = self._streams[stream.stream_key] + if state.received_mappings: + logger.warning(f"Unexpected data in CE134 initiator after mappings: {len(data)} bytes") + raise ValueError("Unexpected data in CE134 initiator after mappings") + + logger.debug("CE134 initiator received refine response") + msg = MsgCE134RefineResponse.from_jam_bytes(JamBytes(data)) + state.received_mappings = True + self._handle_refine_response(stream, msg) + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + state = self._streams[stream.stream_key] + if not state.received_mappings: + logger.debug("CE134 acceptor received mappings") + msg = MsgCE134WorkPackageSharing.from_jam_bytes(JamBytes(data)) + state.received_mappings = True + state.sharing_msg = msg + logger.info(f"ce134_received_workpackage_sharing for core {msg.core_index}") + return + + logger.debug("CE134 acceptor received bundle") + msg = MsgCE134WorkPackageBundle.from_jam_bytes(JamBytes(data)) + self._handle_bundle(stream, msg) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.info("Success with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.info("Success with FIN") + + def on_close(self, stream: JAMStream) -> None: + self._streams.pop(stream.stream_key, None) + + def _handle_bundle(self, stream: JAMStream, msg: MsgCE134WorkPackageBundle) -> None: + logger.info("ce134_received_bundle") + work_report = self.context.app.process_work_package(msg.work_package) + + report_hash = work_report.hash() + signature = self.context.app.config.keys.ed25519.sign(report_hash) + response = MsgCE134RefineResponse(report_hash=report_hash, signature=signature) + stream.conn.send( + stream.stream_id, + stream.create_message(response.to_jam_bytes().to_bytes()), + end_stream=True, + ) + + def _handle_refine_response(self, stream: JAMStream, msg: MsgCE134RefineResponse) -> None: + logger.info("ce134_received_refine_response") + work_report = None + if work_report is not None: + self.context.app.guarantee_work_report(work_report, self.context.app.current_timeslot()) + stream.conn.send(stream.stream_id, b"", end_stream=True) diff --git a/pyjamaz/transport/jamnp_s/protocol/ce135.py b/pyjamaz/transport/jamnp_s/protocol/ce135.py new file mode 100644 index 00000000..0f067ee2 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce135.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +import logging + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce135 import MsgCE135GuaranteedWorkReport +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class CE135Handler(StreamHandler): + kind = JAMStreamKind.CE135_WorkReportDistribution + + def initiate_distribution(self, conn, msg: MsgCE135GuaranteedWorkReport) -> JAMStream: + stream = self.open_outgoing(conn) + logger.info(f"CE135 initiating distribution on stream id: {stream.stream_id}") + conn.send( + stream.stream_id, + stream.create_message(msg.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.warning(f"Unexpected data in CE135 initiator: {len(data)} bytes") + raise ValueError("Unexpected data in CE135 initiator") + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE135 acceptor received work report") + MsgCE135GuaranteedWorkReport.from_jam_bytes(JamBytes(data)) + logger.info("CE135 received work report") + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.info("CE135 distribution successful with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.info("CE135 distribution successful with FIN") diff --git a/pyjamaz/transport/jamnp_s/protocol/ce136.py b/pyjamaz/transport/jamnp_s/protocol/ce136.py new file mode 100644 index 00000000..596f05ee --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce136.py @@ -0,0 +1,48 @@ +from __future__ import annotations + +import logging + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce136 import MsgCE136HashRequest, MsgCE136WorkReport +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class CE136Handler(StreamHandler): + kind = JAMStreamKind.CE136_WorkReportRequest + + def initiate_request(self, conn, msg: MsgCE136HashRequest) -> JAMStream: + stream = self.open_outgoing(conn) + logger.info(f"CE136 initiating request on stream id: {stream.stream_id}") + conn.send( + stream.stream_id, + stream.create_message(msg.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE136 initiator received work report") + msg = MsgCE136WorkReport.from_jam_bytes(JamBytes(data)) + logger.info(f"CE136 received work report of length {len(msg.report)}") + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE136 acceptor received request") + msg = MsgCE136HashRequest.from_jam_bytes(JamBytes(data)) + logger.info(f"CE136 received request for hash {msg.hash.hex()}") + report = MsgCE136WorkReport(report=b"") + stream.conn.send( + stream.stream_id, + stream.create_message(report.to_jam_bytes().to_bytes()), + end_stream=True, + ) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.debug("CE136 request successful with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.debug("CE136 request successful with FIN") diff --git a/pyjamaz/transport/jamnp_s/protocol/ce137.py b/pyjamaz/transport/jamnp_s/protocol/ce137.py new file mode 100644 index 00000000..27584aba --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce137.py @@ -0,0 +1,73 @@ +from __future__ import annotations + +import logging + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce137 import ( + MsgCE137BundleShard, + MsgCE137Justification, + MsgCE137SegmentShard, + MsgCE137ShardRequest, +) +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class CE137Handler(StreamHandler): + kind = JAMStreamKind.CE137_ShardDistribution + + def initiate_request(self, conn, req: MsgCE137ShardRequest) -> JAMStream: + stream = self.open_outgoing(conn) + conn.send( + stream.stream_id, + stream.create_message(req.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + @staticmethod + def _chunks(data: bytes, chunk_size: int): + for idx in range(0, len(data), chunk_size): + yield data[idx : idx + chunk_size] + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE137 initiator received response") + bundle = MsgCE137BundleShard.from_jam_bytes(JamBytes(data[: len(data) // 3])) + segments = [ + MsgCE137SegmentShard.from_jam_bytes(JamBytes(chunk)) + for chunk in self._chunks(data, max(1, len(data) // 3)) + ] + just = MsgCE137Justification.from_jam_bytes(JamBytes(data[-len(data) // 3 :])) + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE137 acceptor received request") + MsgCE137ShardRequest.from_jam_bytes(JamBytes(data)) + bundle = MsgCE137BundleShard(bytes_=b"") + segments = [MsgCE137SegmentShard(bytes_=b"") for _ in range(10)] + just = MsgCE137Justification(bytes_=b"") + stream.conn.send( + stream.stream_id, + stream.create_message(bundle.to_jam_bytes().to_bytes()), + end_stream=False, + ) + for segment in segments: + stream.conn.send( + stream.stream_id, + stream.create_message(segment.to_jam_bytes().to_bytes()), + end_stream=False, + ) + stream.conn.send( + stream.stream_id, + stream.create_message(just.to_jam_bytes().to_bytes()), + end_stream=True, + ) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.info("CE137 success with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.info("CE137 success with FIN") diff --git a/pyjamaz/transport/jamnp_s/protocol/ce138.py b/pyjamaz/transport/jamnp_s/protocol/ce138.py new file mode 100644 index 00000000..b0fc13e5 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce138.py @@ -0,0 +1,56 @@ +from __future__ import annotations + +import logging + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce138 import ( + MsgCE138BundleShard, + MsgCE138Justification, + MsgCE138ShardRequest, +) +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class CE138Handler(StreamHandler): + kind = JAMStreamKind.CE138_AuditShardRequest + + def initiate_request(self, conn, req: MsgCE138ShardRequest) -> JAMStream: + stream = self.open_outgoing(conn) + conn.send( + stream.stream_id, + stream.create_message(req.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE138 initiator received response") + bundle = MsgCE138BundleShard.from_jam_bytes(JamBytes(data[: len(data) // 2])) + just = MsgCE138Justification.from_jam_bytes(JamBytes(data[len(data) // 2 :])) + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE138 acceptor received request") + MsgCE138ShardRequest.from_jam_bytes(JamBytes(data)) + bundle = MsgCE138BundleShard(bytes_=b"") + just = MsgCE138Justification(bytes_=b"") + stream.conn.send( + stream.stream_id, + stream.create_message(bundle.to_jam_bytes().to_bytes()), + end_stream=False, + ) + stream.conn.send( + stream.stream_id, + stream.create_message(just.to_jam_bytes().to_bytes()), + end_stream=True, + ) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.info("CE138 success FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.info("CE138 success FIN") diff --git a/pyjamaz/transport/jamnp_s/protocol/ce139.py b/pyjamaz/transport/jamnp_s/protocol/ce139.py new file mode 100644 index 00000000..93931d4f --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce139.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import logging + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce139 import ( + MsgCE139SegmentRequest, + MsgCE139SegmentShard, +) +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class CE139Handler(StreamHandler): + kind = JAMStreamKind.CE139_SegmentShardRequest + + def initiate_request(self, conn, req: MsgCE139SegmentRequest) -> JAMStream: + stream = self.open_outgoing(conn) + conn.send( + stream.stream_id, + stream.create_message(req.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE139 initiator received shards") + chunk_size = max(1, len(data)) + [ + MsgCE139SegmentShard.from_jam_bytes(JamBytes(chunk)) + for chunk in self._chunks(data, chunk_size) + ] + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE139 acceptor received request") + msg = MsgCE139SegmentRequest.from_jam_bytes(JamBytes(data)) + shards = [MsgCE139SegmentShard(bytes_=b"") for _ in msg.segment_indices] + for shard in shards: + stream.conn.send( + stream.stream_id, + stream.create_message(shard.to_jam_bytes().to_bytes()), + end_stream=(shard == shards[-1]), + ) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.info("CE139 success with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.info("CE139 success with FIN") + + @staticmethod + def _chunks(data: bytes, chunk_size: int): + for idx in range(0, len(data), chunk_size): + yield data[idx : idx + chunk_size] diff --git a/pyjamaz/transport/jamnp_s/protocol/ce140.py b/pyjamaz/transport/jamnp_s/protocol/ce140.py new file mode 100644 index 00000000..4f2b9cc6 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce140.py @@ -0,0 +1,55 @@ +from __future__ import annotations + +import logging + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce140 import ( + MsgCE140Justification, + MsgCE140SegmentRequest, + MsgCE140SegmentShard, +) +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class CE140Handler(StreamHandler): + kind = JAMStreamKind.CE140_SegmentShardRequestJustification + + def initiate_request(self, conn, req: MsgCE140SegmentRequest) -> JAMStream: + stream = self.open_outgoing(conn) + conn.send( + stream.stream_id, + stream.create_message(req.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE140 initiator received shards and justifications") + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE140 acceptor received request") + msg = MsgCE140SegmentRequest.from_jam_bytes(JamBytes(data)) + for idx in msg.segment_indices: + shard = MsgCE140SegmentShard(bytes_=b"") + just = MsgCE140Justification(bytes_=b"") + stream.conn.send( + stream.stream_id, + stream.create_message(shard.to_jam_bytes().to_bytes()), + end_stream=False, + ) + stream.conn.send( + stream.stream_id, + stream.create_message(just.to_jam_bytes().to_bytes()), + end_stream=(idx == msg.segment_indices[-1]), + ) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.info("CE140 success with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.info("CE140 success with FIN") diff --git a/pyjamaz/transport/jamnp_s/protocol/ce141.py b/pyjamaz/transport/jamnp_s/protocol/ce141.py new file mode 100644 index 00000000..0f168ff7 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce141.py @@ -0,0 +1,41 @@ +from __future__ import annotations + +import logging + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce141 import MsgCE141Assurance +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class CE141Handler(StreamHandler): + kind = JAMStreamKind.CE141_AssuranceDistribution + + def initiate_distribution(self, conn, msg: MsgCE141Assurance) -> JAMStream: + stream = self.open_outgoing(conn) + logger.info(f"Initiating assurance distribution on stream id: {stream.stream_id} to {conn.host}:{conn.port}") + conn.send( + stream.stream_id, + stream.create_message(msg.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.warning(f"Unexpected data in CE141 initiator: {len(data)} bytes") + raise ValueError("Unexpected data in CE141 initiator") + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE141 acceptor received assurance") + MsgCE141Assurance.from_jam_bytes(JamBytes(data)) + logger.info("Received assurance") + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.info("Success with code with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.info("Success with code with FIN") diff --git a/pyjamaz/transport/jamnp_s/protocol/ce142.py b/pyjamaz/transport/jamnp_s/protocol/ce142.py new file mode 100644 index 00000000..884eb39b --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce142.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +import logging + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce142 import MsgCE142PreimageAnnouncement +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class CE142Handler(StreamHandler): + kind = JAMStreamKind.CE142_PreimageAnnouncement + + def initiate_announcement(self, conn, msg: MsgCE142PreimageAnnouncement) -> JAMStream: + stream = self.open_outgoing(conn) + logger.info(f"Initiating preimage announcement on stream id: {stream.stream_id} to {conn.host}:{conn.port}") + conn.send( + stream.stream_id, + stream.create_message(msg.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + if len(data) == 0: + return + logger.warning(f"Unexpected data in CE142 initiator: {len(data)} bytes") + raise ValueError("Unexpected data in CE142 initiator") + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE142 acceptor received preimage announcement") + msg = MsgCE142PreimageAnnouncement.from_jam_bytes(JamBytes(data)) + logger.info(f"Received preimage announcement for hash {msg.hash.hex()}") + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.info("Success with code with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.info("Success with code with FIN") diff --git a/pyjamaz/transport/jamnp_s/protocol/ce143.py b/pyjamaz/transport/jamnp_s/protocol/ce143.py new file mode 100644 index 00000000..092a6d94 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce143.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +import logging + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce143 import MsgCE143HashRequest, MsgCE143Preimage +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class CE143Handler(StreamHandler): + kind = JAMStreamKind.CE143_PreimageRequest + + def initiate_request(self, conn, msg: MsgCE143HashRequest) -> JAMStream: + stream = self.open_outgoing(conn) + logger.info(f"CE143 initiating request on stream id: {stream.stream_id}") + conn.send( + stream.stream_id, + stream.create_message(msg.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE143 initiator received preimage") + msg = MsgCE143Preimage.from_jam_bytes(JamBytes(data)) + logger.info(f"CE143 received preimage of length {len(msg.bytes_)}") + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE143 acceptor received preimage request") + msg = MsgCE143HashRequest.from_jam_bytes(JamBytes(data)) + logger.info(f"CE143 received request for hash {msg.hash.hex()}") + preimage = MsgCE143Preimage(bytes_=b"") + stream.conn.send( + stream.stream_id, + stream.create_message(preimage.to_jam_bytes().to_bytes()), + end_stream=True, + ) + + def initiator_fin(self, stream: JAMStream) -> None: + self._request_success(0) + + def acceptor_fin(self, stream: JAMStream) -> None: + self._request_success(0) + + def initiator_reset(self, stream: JAMStream, reset_code: int) -> None: + self._request_failure(reset_code) + + def acceptor_reset(self, stream: JAMStream, reset_code: int) -> None: + self._request_failure(reset_code) + + @staticmethod + def _request_success(reset_code: int) -> None: + logger.info(f"CE143 request successful with code {reset_code}") + + @staticmethod + def _request_failure(reset_code: int) -> None: + logger.debug(f"CE143 received reset code: {reset_code}") + logger.error(f"CE143 request failed with code {reset_code}") diff --git a/pyjamaz/transport/jamnp_s/protocol/ce144.py b/pyjamaz/transport/jamnp_s/protocol/ce144.py new file mode 100644 index 00000000..0433c15c --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce144.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +import logging +from dataclasses import dataclass + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce144 import ( + MsgCE144Announcement, + MsgCE144Evidence, +) +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +@dataclass +class CE144StreamState: + received_announcement: bool = False + + +class CE144Handler(StreamHandler): + kind = JAMStreamKind.CE144_AuditAnnouncement + + def __init__(self, context) -> None: + super().__init__(context) + self._streams = {} + + def init_stream(self, stream: JAMStream) -> None: + self._streams[stream.stream_key] = CE144StreamState() + + def initiate_announcement( + self, + conn, + ann: MsgCE144Announcement, + evidence: MsgCE144Evidence, + ) -> JAMStream: + stream = self.open_outgoing(conn) + conn.send( + stream.stream_id, + stream.create_message(ann.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=False, + ) + conn.send( + stream.stream_id, + stream.create_message(evidence.to_jam_bytes().to_bytes()), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.warning(f"Unexpected data in CE144 initiator: {len(data)} bytes") + raise ValueError("Unexpected data in CE144 initiator") + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + state = self._streams[stream.stream_key] + + if not state.received_announcement: + logger.debug("CE144 acceptor received announcement") + MsgCE144Announcement.from_jam_bytes(JamBytes(data)) + state.received_announcement = True + return + + logger.debug("CE144 acceptor received evidence") + MsgCE144Evidence.from_jam_bytes(JamBytes(data)) + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.info("CE144 success with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.info("CE144 success with FIN") + + def on_close(self, stream: JAMStream) -> None: + self._streams.pop(stream.stream_key, None) diff --git a/pyjamaz/transport/jamnp_s/protocol/ce145.py b/pyjamaz/transport/jamnp_s/protocol/ce145.py new file mode 100644 index 00000000..e4d85c9e --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/ce145.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import logging + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce145 import MsgCE145JudgmentPublication +from pyjamaz.transport.jamnp_s.types import JAMStream, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class CE145Handler(StreamHandler): + kind = JAMStreamKind.CE145_JudgmentPublication + + def initiate_publication(self, conn, msg: MsgCE145JudgmentPublication) -> JAMStream: + stream = self.open_outgoing(conn) + conn.send( + stream.stream_id, + stream.create_message(msg.to_jam_bytes().to_bytes(), add_stream_type=True), + end_stream=True, + ) + return stream + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + logger.warning(f"Unexpected data in CE145 initiator: {len(data)} bytes") + raise ValueError("Unexpected data in CE145 initiator") + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + logger.debug("CE145 acceptor received judgment") + MsgCE145JudgmentPublication.from_jam_bytes(JamBytes(data)) + stream.conn.send(stream.stream_id, b"", end_stream=True) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.info("CE145 success with FIN") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.info("CE145 success with FIN") diff --git a/pyjamaz/transport/jamnp_s/protocol/context.py b/pyjamaz/transport/jamnp_s/protocol/context.py new file mode 100644 index 00000000..6b908b1a --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/context.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Dict + +from pyjamaz.transport.jamnp_s.types import JAMStreamKind + +if TYPE_CHECKING: + from pyjamaz.app import PyjamazApp + from pyjamaz.transport.jamnp_s.peers import PeerRegistry + from pyjamaz.transport.jamnp_s.stream_manager import StreamManager + from pyjamaz.transport.jamnp_s.validator_manager import ValidatorConnectionManager + + +@dataclass +class ProtocolSharedState: + state_requesting_blocks: bool = False + state_warp_sync: bool = True + + +@dataclass +class ProtocolContext: + app: "PyjamazApp" + peer_registry: "PeerRegistry" + validator_manager: "ValidatorConnectionManager" + stream_manager: "StreamManager" + state: ProtocolSharedState + handlers: Dict[JAMStreamKind, object] = field(default_factory=dict) + + @property + def connections(self): + return self.peer_registry.connections + + @property + def state_requesting_blocks(self) -> bool: + return self.state.state_requesting_blocks + + @state_requesting_blocks.setter + def state_requesting_blocks(self, value: bool) -> None: + self.state.state_requesting_blocks = value + + @property + def state_warp_sync(self) -> bool: + return self.state.state_warp_sync + + @state_warp_sync.setter + def state_warp_sync(self, value: bool) -> None: + self.state.state_warp_sync = value + + def register_handler(self, handler) -> None: + self.handlers[handler.kind] = handler + + def get_handler(self, kind: JAMStreamKind): + return self.handlers[kind] diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/__init__.py b/pyjamaz/transport/jamnp_s/protocol/messages/__init__.py new file mode 100644 index 00000000..31f3515c --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/__init__.py @@ -0,0 +1 @@ +"""Per-stream JAMNP-S wire schema modules.""" diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce128.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce128.py new file mode 100644 index 00000000..bcc27526 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce128.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from enum import Enum +from typing import List + +from jamcodec.mixins import Serializable +from jamcodec.types import H256, U8, U32 + +from pyjamaz.models.block import Block +from pyjamaz.transport.jamnp_s.protocol.messages.common import ImplicitVec + + +class MsgCE128BlockRequestDirection(Enum): + ASC = 0 + DESC = 1 + + +@dataclass +class MsgCE128BlockRequest(Serializable): + header_hash: bytes = field(metadata={"codec": H256}) + direction: int = field(metadata={"codec": U8}) + max_blocks: int = field(metadata={"codec": U32}) + + +@dataclass +class MsgCE128BlockRequestResponse(Serializable): + blocks: List[Block] = field(metadata={"codec": ImplicitVec(Block.to_codec_def())}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce129.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce129.py new file mode 100644 index 00000000..dc2e4285 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce129.py @@ -0,0 +1,14 @@ +from __future__ import annotations + +from dataclasses import dataclass, field + +from jamcodec.mixins import Serializable +from jamcodec.types import Array, H256, U8, U32 + + +@dataclass +class MsgCE129KeyRangeRequest(Serializable): + header_hash: bytes = field(metadata={"codec": H256}) + key_start: bytes = field(metadata={"codec": Array(U8, 31)}) + key_end: bytes = field(metadata={"codec": Array(U8, 31)}) + max_size: int = field(metadata={"codec": U32}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce131.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce131.py new file mode 100644 index 00000000..456b4c83 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce131.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +from dataclasses import dataclass, field + +from jamcodec.mixins import Serializable +from jamcodec.types import Array, U8, U32 + + +@dataclass +class MsgCE131SafroleTicket(Serializable): + attempt: int = field(metadata={"codec": U8}) + proof: bytes = field(metadata={"codec": Array(U8, 784)}) + + +@dataclass +class MsgCE131SafroleTicketDistribution(Serializable): + epoch_index: int = field(metadata={"codec": U32}) + ticket: MsgCE131SafroleTicket = field(metadata={"codec": MsgCE131SafroleTicket.to_codec_def()}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce132.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce132.py new file mode 100644 index 00000000..30ce4b5d --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce132.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +from dataclasses import dataclass + +from pyjamaz.transport.jamnp_s.protocol.messages.ce131 import ( + MsgCE131SafroleTicket, + MsgCE131SafroleTicketDistribution, +) + + +@dataclass +class MsgCE132SafroleTicket(MsgCE131SafroleTicket): + pass + + +@dataclass +class MsgCE132SafroleTicketDistribution(MsgCE131SafroleTicketDistribution): + pass diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce133.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce133.py new file mode 100644 index 00000000..57c3f283 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce133.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +from dataclasses import dataclass, field + +from jamcodec.mixins import Serializable +from jamcodec.types import U16, U8, Vec + +from pyjamaz.models.common import WorkPackage + + +@dataclass +class MsgCE133WorkPackageSubmission(Serializable): + core_index: int = field(metadata={"codec": U16}) + work_package: WorkPackage = field(metadata={"codec": WorkPackage.to_codec_def()}) + + +@dataclass +class MsgCE133Extrinsic(Serializable): + bytes_: bytes = field(metadata={"codec": Vec(U8)}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce134.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce134.py new file mode 100644 index 00000000..43e313b3 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce134.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Dict + +from jamcodec.mixins import Serializable +from jamcodec.types import H256, H512, Map, U16 + +from pyjamaz.models.common import WorkPackage + + +@dataclass +class MsgCE134WorkPackageSharing(Serializable): + core_index: int = field(metadata={"codec": U16}) + segment_root_map: Dict[bytes, bytes] = field(metadata={"codec": Map(H256, H256)}) + + +@dataclass +class MsgCE134WorkPackageBundle(Serializable): + work_package: WorkPackage = field(metadata={"codec": WorkPackage.to_codec_def()}) + + +@dataclass +class MsgCE134RefineResponse(Serializable): + report_hash: bytes = field(metadata={"codec": H256}) + signature: bytes = field(metadata={"codec": H512}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce135.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce135.py new file mode 100644 index 00000000..c8cb385e --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce135.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +from dataclasses import dataclass + +from pyjamaz.models.block import Guarantee + + +@dataclass +class MsgCE135GuaranteedWorkReport(Guarantee): + pass diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce136.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce136.py new file mode 100644 index 00000000..b303ab46 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce136.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +from dataclasses import dataclass, field + +from jamcodec.mixins import Serializable +from jamcodec.types import H256, U8, Vec + + +@dataclass +class MsgCE136HashRequest(Serializable): + hash: bytes = field(metadata={"codec": H256}) + + +@dataclass +class MsgCE136WorkReport(Serializable): + report: bytes = field(metadata={"codec": Vec(U8)}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce137.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce137.py new file mode 100644 index 00000000..bd0381a0 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce137.py @@ -0,0 +1,30 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List + +from jamcodec.mixins import Serializable +from jamcodec.types import Array, H256, U8, U16, Vec + +from pyjamaz.transport.jamnp_s.protocol.messages.common import calculate_r + + +@dataclass +class MsgCE137ShardRequest(Serializable): + erasure_root: bytes = field(metadata={"codec": H256}) + shard_index: int = field(metadata={"codec": U16}) + + +@dataclass +class MsgCE137BundleShard(Serializable): + bytes_: bytes = field(metadata={"codec": Vec(U8)}) + + +@dataclass +class MsgCE137SegmentShard(Serializable): + bytes_: bytes = field(metadata={"codec": Array(U8, 4104 // calculate_r())}) + + +@dataclass +class MsgCE137Justification(Serializable): + nodes: List[bytes] = field(metadata={"codec": Vec(Vec(U8))}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce138.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce138.py new file mode 100644 index 00000000..f22355b1 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce138.py @@ -0,0 +1,23 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List + +from jamcodec.mixins import Serializable +from jamcodec.types import H256, U8, U16, Vec + + +@dataclass +class MsgCE138ShardRequest(Serializable): + erasure_root: bytes = field(metadata={"codec": H256}) + shard_index: int = field(metadata={"codec": U16}) + + +@dataclass +class MsgCE138BundleShard(Serializable): + bytes_: bytes = field(metadata={"codec": Vec(U8)}) + + +@dataclass +class MsgCE138Justification(Serializable): + nodes: List[bytes] = field(metadata={"codec": Vec(Vec(U8))}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce139.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce139.py new file mode 100644 index 00000000..65cf7385 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce139.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List + +from jamcodec.mixins import Serializable +from jamcodec.types import Array, H256, U8, U16, Vec + +from pyjamaz.transport.jamnp_s.protocol.messages.common import calculate_r + + +@dataclass +class MsgCE139SegmentRequest(Serializable): + erasure_root: bytes = field(metadata={"codec": H256}) + shard_index: int = field(metadata={"codec": U16}) + segment_indices: List[int] = field(metadata={"codec": Vec(U16)}) + + +@dataclass +class MsgCE139SegmentShard(Serializable): + bytes_: bytes = field(metadata={"codec": Array(U8, 4104 // calculate_r())}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce140.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce140.py new file mode 100644 index 00000000..dc1056fd --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce140.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List + +from jamcodec.mixins import Serializable +from jamcodec.types import Array, H256, U8, U16, Vec + +from pyjamaz.transport.jamnp_s.protocol.messages.common import calculate_r + + +@dataclass +class MsgCE140SegmentRequest(Serializable): + erasure_root: bytes = field(metadata={"codec": H256}) + shard_index: int = field(metadata={"codec": U16}) + segment_indices: List[int] = field(metadata={"codec": Vec(U16)}) + + +@dataclass +class MsgCE140SegmentShard(Serializable): + bytes_: bytes = field(metadata={"codec": Array(U8, 4104 // calculate_r())}) + + +@dataclass +class MsgCE140Justification(Serializable): + nodes: List[bytes] = field(metadata={"codec": Vec(Vec(U8))}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce141.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce141.py new file mode 100644 index 00000000..6cd3b392 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce141.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from dataclasses import dataclass, field + +from jamcodec.mixins import Serializable +from jamcodec.types import H256, H512, U8, Vec + + +@dataclass +class MsgCE141Assurance(Serializable): + header_hash: bytes = field(metadata={"codec": H256}) + bitfield: bytes = field(metadata={"codec": Vec(U8)}) + signature: bytes = field(metadata={"codec": H512}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce142.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce142.py new file mode 100644 index 00000000..af31f5e2 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce142.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +from dataclasses import dataclass, field + +from jamcodec.mixins import Serializable +from jamcodec.types import H256, U32 + + +@dataclass +class MsgCE142PreimageAnnouncement(Serializable): + service_id: int = field(metadata={"codec": U32}) + hash: bytes = field(metadata={"codec": H256}) + preimage_length: int = field(metadata={"codec": U32}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce143.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce143.py new file mode 100644 index 00000000..91cf1ca9 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce143.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +from dataclasses import dataclass, field + +from jamcodec.mixins import Serializable +from jamcodec.types import H256, U8, Vec + + +@dataclass +class MsgCE143HashRequest(Serializable): + hash: bytes = field(metadata={"codec": H256}) + + +@dataclass +class MsgCE143Preimage(Serializable): + bytes_: bytes = field(metadata={"codec": Vec(U8)}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce144.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce144.py new file mode 100644 index 00000000..0ef2c7b2 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce144.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List + +from jamcodec.mixins import Serializable +from jamcodec.types import Array, H256, H512, U8, U16, U32, Vec + + +@dataclass +class MsgCE144CoreWRPair(Serializable): + core_index: int = field(metadata={"codec": U16}) + wr_hash: bytes = field(metadata={"codec": H256}) + + +@dataclass +class MsgCE144Announcement(Serializable): + header_hash: bytes = field(metadata={"codec": H256}) + tranche: int = field(metadata={"codec": U8}) + announcement: List[MsgCE144CoreWRPair] = field(metadata={"codec": Vec(MsgCE144CoreWRPair.to_codec_def())}) + signature: bytes = field(metadata={"codec": H512}) + + +@dataclass +class MsgCE144NoShow(Serializable): + validator_index: int = field(metadata={"codec": U32}) + announcement: bytes = field(metadata={"codec": Vec(U8)}) + + +@dataclass +class MsgCE144TrancheEvidenceFirst(Serializable): + signature: bytes = field(metadata={"codec": Array(U8, 96)}) + + +@dataclass +class MsgCE144TrancheEvidenceSubsequent(Serializable): + signature: bytes = field(metadata={"codec": Array(U8, 96)}) + no_shows: List[MsgCE144NoShow] = field(metadata={"codec": Vec(MsgCE144NoShow.to_codec_def())}) + + +@dataclass +class MsgCE144Evidence(Serializable): + data: bytes = field(metadata={"codec": Vec(U8)}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/ce145.py b/pyjamaz/transport/jamnp_s/protocol/messages/ce145.py new file mode 100644 index 00000000..f23d05f5 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/ce145.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from enum import Enum + +from jamcodec.mixins import Serializable +from jamcodec.types import H256, H512, U8, U32 + + +class JudgmentValidity(Enum): + INVALID = 0 + VALID = 1 + + +@dataclass +class MsgCE145JudgmentPublication(Serializable): + epoch_index: int = field(metadata={"codec": U32}) + validator_index: int = field(metadata={"codec": U32}) + validity: int = field(metadata={"codec": U8}) + wr_hash: bytes = field(metadata={"codec": H256}) + signature: bytes = field(metadata={"codec": H512}) diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/common.py b/pyjamaz/transport/jamnp_s/protocol/messages/common.py new file mode 100644 index 00000000..aec620b9 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/common.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +from jamcodec.base import JamBytes, JamCodecType +from jamcodec.types import Vec + +from pyjamaz.graypaper_constants import VALIDATOR_COUNT + + +class ImplicitVec(Vec): + def encode(self, value: list) -> JamBytes: + data = JamBytes(bytes()) + + for idx, item in enumerate(value): + if type(item) is JamBytes: + data += item + else: + data += self.type_def.encode(item) + if item and issubclass(item.__class__, JamCodecType): + value[idx] = item.serialize() + + return data + + def decode(self, data: JamBytes) -> list: + value = [] + + while True: + obj = self.type_def.new() + obj.decode(data) + value.append(obj) + + if data.get_remaining_length() == 0: + break + + return value + + +def calculate_r() -> int: + return (VALIDATOR_COUNT // 3) + 1 diff --git a/pyjamaz/transport/jamnp_s/protocol/messages/up0.py b/pyjamaz/transport/jamnp_s/protocol/messages/up0.py new file mode 100644 index 00000000..8cc458d1 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/messages/up0.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import List + +from jamcodec.mixins import Serializable +from jamcodec.types import H256, U32, Vec + +from pyjamaz.models.block import Header + + +@dataclass +class MsgUP0Leaf(Serializable): + header_hash: bytes = field(metadata={"codec": H256}) + timeslot: int = field(metadata={"codec": U32}) + + +@dataclass +class MsgUP0Handshake(Serializable): + header_hash: bytes = field(metadata={"codec": H256}) + timeslot: int = field(metadata={"codec": U32}) + leafs: List[MsgUP0Leaf] = field(metadata={"codec": Vec(MsgUP0Leaf.to_codec_def())}) + + +@dataclass +class MsgUP0Announcement(Serializable): + header: Header = field(metadata={"codec": Header.to_codec_def()}) + header_hash: bytes = field(metadata={"codec": H256}) + timeslot: int = field(metadata={"codec": U32}) diff --git a/pyjamaz/transport/jamnp_s/protocol/up0.py b/pyjamaz/transport/jamnp_s/protocol/up0.py new file mode 100644 index 00000000..09fdb09a --- /dev/null +++ b/pyjamaz/transport/jamnp_s/protocol/up0.py @@ -0,0 +1,156 @@ +from __future__ import annotations + +import enum +import logging +from dataclasses import dataclass + +from jamcodec.base import JamBytes + +from pyjamaz.transport.jamnp_s.connection import JAMConnectionDirection +from pyjamaz.transport.jamnp_s.protocol.base import StreamHandler +from pyjamaz.transport.jamnp_s.protocol.messages.ce128 import ( + MsgCE128BlockRequest, + MsgCE128BlockRequestDirection, +) +from pyjamaz.transport.jamnp_s.protocol.messages.up0 import ( + MsgUP0Announcement, + MsgUP0Handshake, +) +from pyjamaz.transport.jamnp_s.types import JAMStream, StreamDirection, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + + +class UPState(enum.Enum): + IN_PROGRESS = 0 + CONNECTED = 1 + + +@dataclass +class UP0StreamState: + phase: UPState = UPState.IN_PROGRESS + + +class UP0Handler(StreamHandler): + kind = JAMStreamKind.UP0_BlockAnnouncement + + def __init__(self, context) -> None: + super().__init__(context) + self._streams = {} + + def init_stream(self, stream: JAMStream) -> None: + self._streams[stream.stream_key] = UP0StreamState() + + def send_handshake(self, conn) -> None: + slot = self.context.app.working_state.timeslot.number + header_hash = self.context.app.retrieve_block_hash(slot) + handshake = MsgUP0Handshake( + header_hash=header_hash, + timeslot=slot, + leafs=[], + ) + logger.info( + f"Send handshake on stream {conn.stream_up.stream_id} to {conn.host}:{conn.port} with hash {header_hash}" + ) + + conn.send( + conn.stream_up.stream_id, + conn.stream_up.create_message( + handshake.to_jam_bytes().to_bytes(), + add_stream_type=conn.direction == JAMConnectionDirection.initiator, + ), + ) + + async def broadcast_block(self, block) -> None: + logger.info(f"Broadcast {block.header.hash.hex()} to {len(self.context.connections)} connections") + + payload = MsgUP0Announcement( + header=block.header, + header_hash=block.header.hash, + timeslot=block.header.timeslot, + ).to_jam_bytes().to_bytes() + + for conn in self.context.connections.values(): + if not conn.is_connected(): + logger.debug( + f"Skipping broadcast to {conn.host}:{conn.port} - connection is not fully established yet" + ) + continue + + logger.debug(f"Send block header to client {conn.host}:{conn.port} with hash {block.header.hash.hex()}") + conn.send( + conn.stream_up.stream_id, + conn.stream_up.create_message(payload), + end_stream=False, + ) + + def initiator_message(self, stream: JAMStream, data: bytes) -> None: + self._receive_message(stream, data) + + def acceptor_message(self, stream: JAMStream, data: bytes) -> None: + self._receive_message(stream, data) + + def initiator_fin(self, stream: JAMStream) -> None: + logger.warning(f"Unexpected FIN on persistent UP0 stream {stream.stream_id}") + + def acceptor_fin(self, stream: JAMStream) -> None: + logger.warning(f"Unexpected FIN on persistent UP0 stream {stream.stream_id}") + + def on_close(self, stream: JAMStream) -> None: + self._streams.pop(stream.stream_key, None) + + def _receive_message(self, stream: JAMStream, data: bytes) -> None: + state = self._streams[stream.stream_key] + + if state.phase == UPState.IN_PROGRESS: + state.phase = UPState.CONNECTED + msg = MsgUP0Handshake.from_jam_bytes(JamBytes(data)) + self._handle_handshake(stream, msg) + return + + if state.phase == UPState.CONNECTED: + msg = MsgUP0Announcement.from_jam_bytes(JamBytes(data)) + self._handle_announcement(stream.conn, msg) + return + + raise RuntimeError(f"Unexpected state {state.phase}") + + def _handle_handshake(self, stream: JAMStream, msg: MsgUP0Handshake) -> None: + if stream.direction == StreamDirection.acceptor: + self.send_handshake(stream.conn) + + if self.context.state_requesting_blocks: + logger.debug("Skipping handshake block header check, already importing blocks") + return + + block = self.context.app.retrieve_block_by_hash(msg.header_hash) + if block: + return + + logger.info(f"Received newer block from handshake: {msg.header_hash} -> initiate CE128RequestBlocks") + self._initiate_block_sync(stream.conn, msg.header_hash) + + def _handle_announcement(self, conn, msg: MsgUP0Announcement) -> None: + if self.context.state_requesting_blocks: + logger.debug("Skipping block header announcement check, already importing blocks") + return + + block = self.context.app.retrieve_block_by_hash(msg.header.hash) + if block: + return + + logger.info(f"Received new block announcement from up0: {msg.header.hash}") + self._initiate_block_sync(conn, announced_hash=msg.header.hash) + + def _initiate_block_sync(self, conn, announced_hash: bytes) -> None: + self.context.state_requesting_blocks = True + curr_hash = self.context.app.retrieve_block_hash(self.context.app.working_state.timeslot.number) + ce128_handler = self.context.get_handler(JAMStreamKind.CE128_BlockRequest) + ce128_handler.initiate_block_request( + conn, + MsgCE128BlockRequest( + curr_hash, + MsgCE128BlockRequestDirection.ASC.value, + 10, + ), + ) diff --git a/pyjamaz/transport/jamnp_s/stream_manager.py b/pyjamaz/transport/jamnp_s/stream_manager.py new file mode 100644 index 00000000..2a8da80b --- /dev/null +++ b/pyjamaz/transport/jamnp_s/stream_manager.py @@ -0,0 +1,242 @@ +from __future__ import annotations + +import logging +from typing import Dict, Tuple, TYPE_CHECKING + +from pyjamaz.transport.jamnp_s.types import IStreamHandler, JAMStream, StreamDirection, JAMStreamKind + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + +if TYPE_CHECKING: + from pyjamaz.transport.jamnp_s.connection import JAMConnection + + +class StreamManager: + + def __init__(self, max_message_size: int) -> None: + self.max_message_size = max_message_size + self.handlers: Dict[JAMStreamKind, IStreamHandler] = {} + self._streams: Dict[Tuple[int, int], JAMStream] = {} + self._pending_streams: Dict[Tuple[int, int], bytearray] = {} + + + def register_handler(self, handler: IStreamHandler) -> None: + self.handlers[handler.kind] = handler + + + def open_outgoing(self, connection: "JAMConnection", kind: JAMStreamKind) -> JAMStream: + stream_id = connection._quic.get_next_available_stream_id() + stream = JAMStream( + stream_id=stream_id, + stream_kind=kind, + conn=connection, + direction=StreamDirection.initiator, + ) + self.register_stream(stream) + return stream + + + def receive_stream_data( + self, + connection: "JAMConnection", + stream_id: int, + data: bytes, + end_stream: bool = False, + ) -> None: + + stream = self._streams.get(self.get_stream_key(connection, stream_id)) + + if stream is None: + stream = self.determine_stream_kind(connection, stream_id, data, end_stream) + if stream is None: + return + + pending = self._pending_streams.pop(self.get_stream_key(connection, stream_id), bytearray()) + data = bytes(pending[1:]) + + self._parse_bytes(stream, data, end_stream) + + + def receive_reset(self, connection: "JAMConnection", stream_id: int, reset_code: int) -> None: + key = self.get_stream_key(connection, stream_id) + stream = self._streams.get(key) + if stream is None: + self._pending_streams.pop(key, None) + logger.debug(f"Connection {connection.jam_connection_ulid} QUIC stream {stream_id} already closed") + return + + logger.info( + f"Connection {connection.jam_connection_ulid} QUIC StreamReset {stream.stream_kind} ({stream_id}) direction={stream.direction} code {reset_code}" + ) + + try: + if stream.handler is not None: + stream.handler.on_reset(stream, reset_code) + finally: + self._cleanup_stream(stream) + + + def send_reset(self, stream: JAMStream, reset_code: int) -> None: + stream.conn.reset_stream(stream.stream_id, reset_code) + self._cleanup_stream(stream) + + + def close_stream(self, stream: JAMStream, reason: int = 0, clean_close: bool = True) -> None: + stream.conn.close_stream(stream.stream_id, clean_close=clean_close, reason=reason) + self._cleanup_stream(stream) + + + def cleanup_connection(self, connection: "JAMConnection") -> None: + conn_key = id(connection) + + for key, stream in list(self._streams.items()): + if key[0] != conn_key: + continue + self._cleanup_stream(stream) + + for key in [key for key in self._pending_streams if key[0] == conn_key]: + self._pending_streams.pop(key, None) + + connection.streams.clear() + connection.stream_up = None + + + def determine_stream_kind( + self, + connection: "JAMConnection", + stream_id: int, + data: bytes, + end_stream: bool, + ) -> JAMStream | None: + key = self.get_stream_key(connection, stream_id) + pending = self._pending_streams.setdefault(key, bytearray()) + if data: + pending.extend(data) + + if len(pending) < 1: + if end_stream: + self._reset_unknown_stream( + connection, stream_id, JAMStream.ERROR_INVALID_MESSAGE, "Stream ended before stream kind was received" + ) + return None + + try: + kind = JAMStreamKind(pending[0]) + except ValueError: + self._reset_unknown_stream( + connection, + stream_id, + JAMStream.ERROR_INVALID_MESSAGE, + f"QUIC stream {stream_id} is not mapped (type {pending[0]})", + ) + return None + + stream = JAMStream( + stream_id=stream_id, + stream_kind=kind, + conn=connection, + direction=StreamDirection.acceptor, + ) + self.register_stream(stream) + return stream + + + def _parse_bytes(self, stream: JAMStream, data: bytes, end_stream: bool) -> None: + if data: + stream.recv_buffer.extend(data) + + try: + while True: + if stream.expected_len is None: + if len(stream.recv_buffer) < 4: + break + + stream.expected_len = int.from_bytes(stream.recv_buffer[:4], byteorder="little") + del stream.recv_buffer[:4] + + logger.debug( + f"Received new message for stream {stream.stream_id} with a msg length: {stream.expected_len} ({len(stream.recv_buffer)} buffered)" + ) + + if stream.expected_len <= 0: + raise ValueError(f"Message size <= 0 for stream {stream.stream_id} {stream.expected_len}") + if stream.expected_len > self.max_message_size: + raise MemoryError(f"Message too large for stream {stream.stream_id}") + + if len(stream.recv_buffer) < stream.expected_len: + break + + message = bytes(stream.recv_buffer[:stream.expected_len]) + del stream.recv_buffer[:stream.expected_len] + stream.expected_len = None + + logger.debug(f"Message complete for stream {stream.stream_id}") + if stream.handler is not None: + stream.handler.on_message(stream, message) + + if stream.closed: + return + + if not end_stream: + return + + if stream.expected_len is not None or len(stream.recv_buffer) > 0: + raise ValueError(f"Incomplete framed message on FIN for stream {stream.stream_id}") + + logger.debug(f"Received FIN on stream {stream.stream_id}") + if stream.handler is not None: + stream.handler.on_fin(stream) + except Exception as exc: + stream.handle_error(exc) + return + + self._cleanup_stream(stream) + + + def register_stream(self, stream: JAMStream) -> None: + handler = self.handlers.get(stream.stream_kind) + if handler is None: + raise ValueError(f"Unsupported stream kind: {stream.stream_kind}") + + stream.handler = handler + self._streams[self.get_stream_key(stream.conn, stream.stream_id)] = stream + stream.conn.streams[stream.stream_id] = stream + if stream.stream_kind == JAMStreamKind.UP0_BlockAnnouncement: + stream.conn.stream_up = stream + + handler.init_stream(stream) + + + def _cleanup_stream(self, stream: JAMStream) -> None: + if stream.closed: + return + + stream.closed = True + + if stream.handler is not None: + on_close = getattr(stream.handler, "on_close", None) + if callable(on_close): + on_close(stream) + + self._streams.pop(self.get_stream_key(stream.conn, stream.stream_id), None) + stream.conn.streams.pop(stream.stream_id, None) + + if stream.conn.stream_up is stream: + stream.conn.stream_up = None + + + def _reset_unknown_stream( + self, + connection: "JAMConnection", + stream_id: int, + error_code: int, + reason: str, + ) -> None: + logger.error(reason) + connection.reset_stream(stream_id, error_code) + self._pending_streams.pop(self.get_stream_key(connection, stream_id), None) + + + @staticmethod + def get_stream_key(connection: "JAMConnection", stream_id: int) -> Tuple[int, int]: + return id(connection), stream_id diff --git a/pyjamaz/transport/jamnp_s/types.py b/pyjamaz/transport/jamnp_s/types.py new file mode 100644 index 00000000..338faf15 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/types.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +import logging +from dataclasses import dataclass, field +from enum import Enum, IntEnum +from typing import Optional, Protocol, TYPE_CHECKING + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + +if TYPE_CHECKING: + from pyjamaz.transport.jamnp_s.connection import JAMConnection + + +class JAMStreamKind(IntEnum): + UP0_BlockAnnouncement = 0 + CE128_BlockRequest = 128 + CE129_StateRequest = 129 + CE131_SafroleTicketDistributionStep1 = 131 + CE132_SafroleTicketDistributionStep2 = 132 + CE133_WorkPackageSubmission = 133 + CE134_WorkPackageSharing = 134 + CE135_WorkReportDistribution = 135 + CE136_WorkReportRequest = 136 + CE137_ShardDistribution = 137 + CE138_AuditShardRequest = 138 + CE139_SegmentShardRequest = 139 + CE140_SegmentShardRequestJustification = 140 + CE141_AssuranceDistribution = 141 + CE142_PreimageAnnouncement = 142 + CE143_PreimageRequest = 143 + CE144_AuditAnnouncement = 144 + CE145_JudgmentPublication = 145 + + +class StreamDirection(Enum): + initiator = 0 + acceptor = 1 + + +class IStreamHandler(Protocol): + kind: JAMStreamKind + + def init_stream(self, stream: "JAMStream") -> None: + ... + + def on_message(self, stream: "JAMStream", data: bytes) -> None: + ... + + def on_fin(self, stream: "JAMStream") -> None: + ... + + def on_reset(self, stream: "JAMStream", reset_code: int) -> None: + ... + + def on_close(self, stream: "JAMStream") -> None: + ... + + +@dataclass +class JAMStream: + stream_id: int + stream_kind: JAMStreamKind + conn: "JAMConnection" + direction: StreamDirection + handler: Optional[IStreamHandler] = field(default=None, repr=False) + closed: bool = False + recv_buffer: bytearray = field(default_factory=bytearray, repr=False) + expected_len: Optional[int] = field(default=None, repr=False) + stream_type: int = field(init=False) + stream_type_byte: bytes = field(init=False) + + ERROR_GENERAL = 1 + ERROR_INVALID_MESSAGE = 2 + ERROR_INVALID_SIZE = 3 + ERROR_TOO_LARGE = 4 + ERROR_VALIDATION_FAILED = 5 + + def __post_init__(self) -> None: + self.stream_type = int(self.stream_kind) + self.stream_type_byte = self.stream_type.to_bytes(length=1, byteorder="little") + + @property + def protocol(self): + return self.conn.protocol + + @property + def stream_key(self): + return self.conn.jam_connection_ulid, self.stream_id + + def create_message(self, payload: bytes, add_stream_type: bool = False) -> bytes: + msg = len(payload).to_bytes(length=4, byteorder="little") + payload + if add_stream_type: + return self.stream_type_byte + msg + return msg + + def close(self, reason: int = 0, clean_close: bool = True) -> None: + if self.closed: + return + self.conn.stream_manager.close_stream(self, reason=reason, clean_close=clean_close) + + def send_reset(self, reset_code: int) -> None: + if self.closed: + return + self.conn.stream_manager.send_reset(self, reset_code) + + def handle_error(self, exc: Exception) -> None: + if isinstance(exc, ValueError): + code = self.ERROR_INVALID_MESSAGE + elif isinstance(exc, MemoryError): + code = self.ERROR_TOO_LARGE + else: + code = self.ERROR_GENERAL + + logger.error(f"Stream {self.stream_id} error: {exc}") + self.send_reset(code) diff --git a/pyjamaz/transport/jamnp_s/validator_manager.py b/pyjamaz/transport/jamnp_s/validator_manager.py new file mode 100644 index 00000000..7abe53a8 --- /dev/null +++ b/pyjamaz/transport/jamnp_s/validator_manager.py @@ -0,0 +1,305 @@ +from __future__ import annotations + +import logging +import math +import time +from base64 import b32encode +from dataclasses import dataclass +from enum import IntEnum +from typing import Awaitable, Callable, Dict, Iterable, Optional, TYPE_CHECKING + +from aioquic.quic.connection import QuicConnectionState + +from pyjamaz import settings + +logger = logging.getLogger("pyjamaz.transport.jamnp_s") + +if TYPE_CHECKING: + from pyjamaz.app import PyjamazApp + from pyjamaz.models.common import ValidatorData + from pyjamaz.transport.jamnp_s.connection import JAMConnection + + +ConnectCallback = Callable[[str, int, Optional[bytes]], Awaitable[None]] +DisconnectCallback = Callable[["JAMConnection", Optional[bytes]], None] + + +@dataclass +class ValidatorConnection: + validator: ValidatorData + ip: str + port: int + connection: Optional["JAMConnection"] = None + last_try: Optional[float] = None + desired_since: Optional[float] = None + initiator: bool = False + in_grid: bool = False + + +class ValidatorConnectionManager: + FALLBACK_INITIATOR_TIMEOUT = 5.0 + RETRY_INTERVAL = 3.0 + + def __init__( + self, + app: "PyjamazApp", + connect_callback: ConnectCallback, + disconnect_callback: DisconnectCallback, + port_override: Optional[int] = None, + ) -> None: + self.app = app + self.connect_callback = connect_callback + self.disconnect_callback = disconnect_callback + self.port_override = port_override + self.connections: Dict[bytes, ValidatorConnection] = {} + + self.validator = None + self.validator_dns = None + self.validator_port = None + self.validator_address = None + self.refresh_local_validator() + + + def refresh_local_validator(self) -> None: + self.validator = None + self.validator_dns = None + self.validator_port = None + self.validator_address = None + + if self.app.config.keys is None: + return + + for validator in self._validator_sets(): + if validator.ed25519 == self.app.config.keys.ed25519.public_key: + self.validator = validator + self.validator_address, self.validator_port = self.get_validator_endpoint(validator) + peer_id = b32encode(validator.ed25519).decode("ascii").lower().rstrip("=") + self.validator_dns = f"e{peer_id}@{self.validator_address}:{self.validator_port}" + return + + + def _validator_sets(self) -> Iterable[ValidatorData]: + yield from self.app.working_state.validator_queue.validators + yield from self.app.working_state.validator_pool.validators + yield from self.app.working_state.validator_archive.validators + + + @staticmethod + def should_initiate_connection(validator_a: bytes, validator_b: bytes) -> bool: + connect_a = 1 if validator_a[31] > 127 else 0 + connect_b = 1 if validator_b[31] > 127 else 0 + a_less = 1 if validator_a < validator_b else 0 + return (connect_a ^ connect_b ^ a_less) == 1 + + + def _debug_validator_override(self, validator: "ValidatorData") -> Optional[tuple[str, int]]: + overrides = getattr(settings, "VALIDATOR_ENDPOINT_OVERRIDES", {}) or {} + value = overrides.get(f"0x{validator.ed25519.hex()}") + if value is None: + value = overrides.get(validator.ed25519.hex()) + + if isinstance(value, str): + host, sep, port_str = value.rpartition(":") + if not sep: + raise ValueError(f"Invalid validator endpoint override: {value!r}") + return host, int(port_str) + + if isinstance(value, (tuple, list)) and len(value) == 2: + host, port = value + return str(host), int(port) + + if value is None: + return None + + raise ValueError(f"Unsupported validator endpoint override: {value!r}") + + + def get_validator_endpoint(self, validator: ValidatorData) -> tuple[str, int]: + override = self._debug_validator_override(validator) + if override is not None: + return override + + ip = validator.get_metadata_ipaddress() + port = validator.get_metadata_port() + if self.port_override is not None and self.validator is not None: + port_delta = self.port_override - self.validator.get_metadata_port() + port += port_delta + return ip, port + + + def get_neighbors( + self, + validator_set: list[ValidatorData], + local_key: bytes, + other_sets: Iterable[list[ValidatorData]], + ) -> Dict[bytes, ValidatorData]: + local_index = next( + (index for index, validator in enumerate(validator_set) if validator.ed25519 == local_key), + None, + ) + if local_index is None: + return {} + + neighbors: Dict[bytes, ValidatorData] = {} + width = max(1, math.floor(math.sqrt(len(validator_set)))) + local_row = local_index // width + local_column = local_index % width + + for index, validator in enumerate(validator_set): + if (index // width) == local_row or (index % width) == local_column: + neighbors[validator.ed25519] = validator + + for other_set in other_sets: + if local_index < len(other_set): + validator = other_set[local_index] + neighbors[validator.ed25519] = validator + + neighbors.pop(local_key, None) + return neighbors + + + def build_grid_neighbors(self) -> Dict[bytes, ValidatorData]: + if self.validator is None: + return {} + + prev_validators = self.app.working_state.validator_archive.validators + current_validators = self.app.working_state.validator_pool.validators + next_validators = self.app.working_state.validator_queue.validators + + neighbors: Dict[bytes, ValidatorData] = {} + local_key = self.validator.ed25519 + + for validator in self.get_neighbors(prev_validators, local_key, [current_validators, next_validators]).values(): + neighbors[validator.ed25519] = validator + for validator in self.get_neighbors(current_validators, local_key, []).values(): + neighbors[validator.ed25519] = validator + for validator in self.get_neighbors(next_validators, local_key, []).values(): + neighbors[validator.ed25519] = validator + + return neighbors + + + @staticmethod + def is_connection_active(connection: Optional["JAMConnection"]) -> bool: + if connection is None: + return False + + quic = getattr(connection, "_quic", None) + if quic is None: + return False + + if getattr(quic, "_close_pending", False): + return False + + state = getattr(quic, "_state", None) + if state is None: + return False + + terminal_states = { + QuicConnectionState.CLOSING, + QuicConnectionState.DRAINING, + QuicConnectionState.TERMINATED, + } + return state not in terminal_states + + + def has_tracked_validator(self, validator_key: bytes) -> bool: + return validator_key in self.connections + + + async def update_validator_connections(self) -> None: + self.refresh_local_validator() + + if not self.validator: + return + + now = time.time() + new_neighbors = self.build_grid_neighbors() + new_keys = set(new_neighbors) + current_keys = set(self.connections) + + for ed25519 in current_keys - new_keys: + state = self.connections.pop(ed25519, None) + if state and state.connection is not None: + self.disconnect_callback(state.connection, ed25519) + + for ed25519 in new_keys: + validator = new_neighbors[ed25519] + overrides = getattr(settings, "VALIDATOR_ENDPOINT_OVERRIDES", {}) or {} + override_key = f"0x{validator.ed25519.hex()}" + if ( + (override_key in overrides and overrides[override_key] is None) + or (validator.ed25519.hex() in overrides and overrides[validator.ed25519.hex()] is None) + ): + continue + is_initiator = self.should_initiate_connection(self.validator.ed25519, validator.ed25519) + in_grid = True + ip, port = self.get_validator_endpoint(validator) + + state = self.connections.get(ed25519) + if state is None: + state = ValidatorConnection( + validator=validator, + ip=ip, + port=port, + initiator=is_initiator, + in_grid=in_grid, + desired_since=now, + ) + self.connections[ed25519] = state + else: + state.validator = validator + state.ip = ip + state.port = port + state.initiator = is_initiator + state.in_grid = in_grid + if state.desired_since is None: + state.desired_since = now + + if self.is_connection_active(state.connection): + continue + + state.connection = None + + if state.last_try is not None and (now - state.last_try) < self.RETRY_INTERVAL: + continue + + should_attempt = state.initiator + if ( + not should_attempt + and state.desired_since is not None + and (now - state.desired_since) >= self.FALLBACK_INITIATOR_TIMEOUT + ): + should_attempt = True + + if not should_attempt: + continue + + state.last_try = now + await self.connect_callback(state.ip, state.port, ed25519) + + + def bind_connection(self, validator_key: bytes, connection: "JAMConnection") -> None: + connection.validator_key = validator_key + state = self.connections.get(validator_key) + if state is None: + return + + if state.connection is not None and state.connection is not connection: + self.disconnect_callback(state.connection, validator_key) + + state.connection = connection + state.last_try = time.time() + + + def on_disconnect(self, connection: "JAMConnection", validator_key: Optional[bytes] = None) -> None: + validator_key = validator_key or getattr(connection, "validator_key", None) + if validator_key is None: + return + + state = self.connections.get(validator_key) + if state is None: + return + + if state.connection is connection: + state.connection = None diff --git a/pyjamaz/transport/protocol_fs.py b/pyjamaz/transport/protocol_fs.py deleted file mode 100644 index cb5a4029..00000000 --- a/pyjamaz/transport/protocol_fs.py +++ /dev/null @@ -1,81 +0,0 @@ -import json -import logging -import os -import anyio -from jamcodec.base import JamBytes - -from pyjamaz.constants import MESSAGE_TYPES -from pyjamaz.models.block import Block -from pyjamaz.transport.pubsub import PubSubSignal -from pyjamaz.transport.types import ProtocolType - - -logger = logging.getLogger("pyjamaz.transport") - - -class FSProtocol(ProtocolType): - - def __init__(self, block_dir, app): - self.block_dir = block_dir - self.lock = anyio.Lock() - self.pubsub = app.pubsub - self.app = app - - async def listen(self): - - seen_files = set() - - while True: - # Run the directory check in a separate thread (non-blocking) - new_files = await anyio.to_thread.run_sync( - lambda: {f for f in os.listdir(self.block_dir) if f.startswith('block-')} - seen_files - ) - - if new_files: - for filename in sorted(new_files): - filepath = os.path.join(self.block_dir, filename) - - try: - async with self.lock: - - with open(filepath, 'r') as file: - if filename.startswith("block-req-"): - await self.pubsub.publish(PubSubSignal(topic=MESSAGE_TYPES.REQUESTED_BLOCKS, data=json.load(file))) - - else: - await self.pubsub.publish(PubSubSignal(topic=MESSAGE_TYPES.RECEIVED_BLOCK,data=json.load(file))) - - except Exception as e: - logging.error(f"Failed to process {filepath}: {e}") - - # Update the seen_files set to include the newly processed files - seen_files.update(new_files) - - await anyio.sleep(.5) - - - async def request_blocks(self, direction, max_blocks, block_bytes): - block = Block.from_jam_bytes(JamBytes(block_bytes)) - blocks = [] - # TODO: take direction and max_blocks into account - # TODO: we decode and serialize blocks unnecessary here, improve! - while block.header.parent != bytes(32): - block = self.app.retrieve_block_by_hash(block.header.parent) - if not block: - break - blocks.append(block) - - serialized_blocks = [b.to_json() for b in blocks] - - filepath = os.path.join(self.block_dir, f'block-req-{block.header.timeslot:06}.json') - with open(filepath, 'w') as file: - json.dump(serialized_blocks, file, indent=2) - - - async def broadcast_block(self, block): - # write block to dir - async with self.lock: - filepath = os.path.join(self.block_dir, f'block-{block.header.timeslot:06}.json') - with open(filepath, 'w') as file: - logger.debug(f"FSProtocol dump block to disk: {filepath}") - json.dump(block.to_json(), file, indent=2) diff --git a/pyjamaz/transport/protocol_jamnp_s.py b/pyjamaz/transport/protocol_jamnp_s.py deleted file mode 100644 index 7cea136b..00000000 --- a/pyjamaz/transport/protocol_jamnp_s.py +++ /dev/null @@ -1,386 +0,0 @@ -import logging -import ssl -from doctest import debug -from enum import Enum - -from typing import Dict, Optional -from typing import Optional, cast - -from aioquic.asyncio import QuicConnectionProtocol, serve -from aioquic.quic.configuration import QuicConfiguration -from aioquic.quic.events import QuicEvent, StreamDataReceived, ConnectionTerminated, HandshakeCompleted -from aioquic.quic.logger import QuicFileLogger -from aioquic.tls import SessionTicket - -from aioquic.asyncio.client import connect -from jamcodec.base import JamBytes -from jamcodec.types import Vec - -from pyjamaz.constants import MESSAGE_TYPES -from pyjamaz.models.block import Block -from pyjamaz.transport.pubsub import PubSubSignal -from pyjamaz.transport.types import ProtocolType - - -logger = logging.getLogger("pyjamaz.transport") - - -def wrap_protocol(wrapper, protocol): - def create_protocol(*args, **kwargs): - instance = protocol(*args, **kwargs) - instance.wrapper = wrapper - return instance - - return create_protocol - - -class InvalidJAMNPSMessage(Exception): - pass - - -class JAMNPSProtocol(QuicConnectionProtocol): - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.wrapper = None # Note: should be set in wrap_protocol - self.stream_up_0 = None - #TODO: this buffer should be made per stream_id (for now, we always assume stream_up_0) - self._msg_buffer = b"" - self._msg_len = -1 - self._msg_type = -1 - self._msg_offset = -1 - - def _reset_msg(self): - self._msg_buffer = b"" - self._msg_len = -1 - self._msg_type = -1 - self._msg_offset = -1 - - def build_handshake_message(self): - #TODO: implement handshake response according to JAMSNP - """Both sides should begin by sending a handshake message containing all known leaves (descendants of the latest finalized block with no known children).""" - logger.debug(f"Building handshake message for UP-0 stream") - return ( - int(JAMNPS.MSG.UP0_OPEN.value).to_bytes( - length=1, - byteorder='little' - ) + - int(0).to_bytes( - length=4, - byteorder='little' - ) - ) - - -class ServerProtocol(JAMNPSProtocol): - - async def send_block_announcement(self, block_bytes): - if self.stream_up_0 is None: - raise Exception("NO UP 0 block_announcement channel opend yet??") - - """ - TODO: - For now we only send length++, we should send: - Final = Header Hash ++ Slot - Leaf = Header Hash ++ Slot - Handshake = Final ++ len++[Leaf] - Announcement = Header ++ Final - """ - self._quic.send_stream_data( - self.stream_up_0, - (int(JAMNPS.MSG.UP0_BlockAnnouncement.value).to_bytes(length=1, byteorder='little') + - len(block_bytes).to_bytes(length=4, byteorder='little') + - block_bytes) - ) - self.transmit() - logger.debug(f"ServerProtocol Block announcement sent to stream {self.stream_up_0} ({len(block_bytes)})") - - def quic_event_received(self, event: QuicEvent): - if isinstance(event, HandshakeCompleted): - # TODO: check client certificate and alpn - # if self._quic.configuration.alpn_protocols[0] != "jamnp-s/0/00000000": - # self._quic.close() - # return - - self.client_id = id(self) - self.wrapper.conn_in[self.client_id] = self # Store reference for broadcasting - - logger.debug(f'ServerProtocol new connected client #{self.client_id}') - - #TODO: remove connections on connection closed/lost etc - - elif isinstance(event, StreamDataReceived): - logger.debug(f'Server received data: {event.data}') - - if self.stream_up_0 is None: - self.stream_up_0 = event.stream_id - logger.debug(f'ServerProtocol new UP-0 stream ({self.stream_up_0}) for client #{self.client_id}') - - # if event.stream_id == self.stream_up_0: - # # Process incoming data (either handshake or announcement) - # logger.debug(f'ServerProtocol new UP-0 stream ({self.stream_up_0}) for client #{self.client_id}') - - byte_data = bytes(event.data) - bytes_left = byte_data - - # Note: Parse bytes until stream data is empty: https://github.com/microsoft/msquic/discussions/2037 - while len(bytes_left) > 0: - - #TODO: do this per channel - if not self._msg_buffer: - # Note: first message always contains expected message type & length - # TODO: kunnen msg_type en msg_len ook opgesplitst zijn in 2 messages?? gaan nu uit dat dit atomair is - self._msg_type = int.from_bytes(byte_data[0:1], byteorder='little') - self._msg_offset = 5 - self._msg_len = int.from_bytes(byte_data[1:5], byteorder='little') + self._msg_offset - logger.debug(f'ServerProtocol new message {self._msg_type} ({self._msg_len} bytes)') - - nr_bytes_remaining = self._msg_len-len(self._msg_buffer) - if nr_bytes_remaining > 0: - self._msg_buffer += bytes_left[:nr_bytes_remaining] - bytes_left = bytes_left[nr_bytes_remaining:] - else: - bytes_left = bytes() - - # If we assembled a new message, parse it - if 0 < self._msg_len == len(self._msg_buffer): - - match self._msg_type: - - case JAMNPS.MSG.UP0_OPEN.value: - logger.debug(f'ServerProtocol PARSED UP-0') - self._reset_msg() - - case JAMNPS.MSG.CE128_BlockRequest.value: - logger.debug(f'ServerProtocol RECEIVED NEW BLOCKSREQUEST') - direction = 1#self._msg_buffer[self._msg_offset:self._msg_offset+1] - max_blocks = 1000 #self._msg_buffer[self._msg_offset+1:self._msg_offset+1+4] - block = Block.from_jam_bytes(JamBytes(self._msg_buffer[self._msg_offset:self._msg_len])) - - logger.debug( - f"ServerProtocol Block Requests received {self.stream_up_0} direction: {direction}, max_blocks: {max_blocks}, block: {block.header.timeslot}") - - blocks = [] - #TODO: take direction and max_blocks into account - #TODO: we decode and serialize blocks unnecessary here, improve! - #TODO: check the max blocks and a hardcoded max of X - while block.header.parent != bytes(32): - block = self.wrapper.app.retrieve_block_by_hash(block.header.parent) - if not block: - break - blocks.append(block) - - block_list = Vec(Block.to_codec_def()).new() - - serialized_blocks = block_list.encode([b.to_jam_bytes() for b in blocks]) - - logger.debug( - f"ServerProtocol Block Requests sending {len(blocks)} blocks") - - self._quic.send_stream_data( - self.stream_up_0, - (int(JAMNPS.MSG.CE128_BlockRequest.value).to_bytes(length=1, byteorder='little') + - len(serialized_blocks).to_bytes(length=4, byteorder='little') + - serialized_blocks.to_bytes()) - ) - self.transmit() - self._reset_msg() - - case _: - raise InvalidJAMNPSMessage(f"Invalid JAMNPS message: {self._msg_type}") - - elif isinstance(event, ConnectionTerminated): - # Handle connection termination - if id(self) in self.wrapper.conn_in: - logger.debug(f'Client #{self.client_id} disconnected') - # print(f'Client #{self.client_id} disconnected') - del self.wrapper.conn_in[id(self)] - - -class ClientProtocol(JAMNPSProtocol): - - async def send_blocks_request(self, direction, max_blocks, block_bytes): - #TODO: moet over een nieuwe stream/connectie?? misbruiken voor nu de up0 stream - data = ( - # int(direction).to_bytes(length=1, byteorder='little') + - # int(max_blocks).to_bytes(length=1, byteorder='little') + - block_bytes - ) - self._quic.send_stream_data( - self.stream_up_0, - (int(JAMNPS.MSG.CE128_BlockRequest.value).to_bytes(length=1, byteorder='little') + - len(data).to_bytes(length=4, byteorder='little') + - data) - ) - self.transmit() - logger.debug(f"ClientProtocol Block Requests sent to stream {self.stream_up_0} ({len(data)})") - - - def quic_event_received(self, event: QuicEvent) -> None: - logger.debug(f'ClientProtocol received data') - - if isinstance(event, StreamDataReceived): - - #TODO: for now we only support 1 stream (UP-0) - #stream_id = event.stream_id - #stream = self._get_or_create_stream(stream_id) - - byte_data = bytes(event.data) - bytes_left = byte_data - - # Note: Parse bytes until stream data is empty: https://github.com/microsoft/msquic/discussions/2037 - while len(bytes_left) > 0: - - #TODO: do this per channel - if not self._msg_buffer: - # Note: first message always contains expected message type & length - self._msg_type = int.from_bytes(byte_data[0:1], byteorder='little') - self._msg_offset = 5 - self._msg_len = int.from_bytes(byte_data[1:5], byteorder='little') + self._msg_offset - logger.debug(f'ClientProtocol new message {self._msg_type} (received {len(bytes_left)-5} of {self._msg_len} bytes)') - - nr_bytes_remaining = self._msg_len-len(self._msg_buffer) - self._msg_buffer += bytes_left[:nr_bytes_remaining] - bytes_left = bytes_left[nr_bytes_remaining:] - - # If we assembled a new message, parse it - if 0 < self._msg_len == len(self._msg_buffer): - - try: - match self._msg_type: - - case JAMNPS.MSG.UP0_BlockAnnouncement.value: - logger.debug(f'ClientProtocol RECEIVED_BLOCK: {self._msg_len}') - self.wrapper.broadcaster.send_stream.send_nowait(PubSubSignal(topic=MESSAGE_TYPES.RECEIVED_BLOCK, data=self._msg_buffer[self._msg_offset:self._msg_len])) - # self.wrapper.broadcaster.send_stream.send_nowait({ - # "message_type": MESSAGE_TYPES.RECEIVED_BLOCK, - # "data": self._msg_buffer[self._msg_offset:self._msg_len] - # }) - - case JAMNPS.MSG.CE128_BlockRequest.value: - logger.debug(f'ClientProtocol RECEIVED REQUESTED BLOCKS: {self._msg_len}') - self.wrapper.broadcaster.send_stream.send_nowait(PubSubSignal(topic=MESSAGE_TYPES.REQUESTED_BLOCKS, - data=self._msg_buffer[self._msg_offset:self._msg_len])) - # self.wrapper.broadcaster.send_stream.send_nowait({ - # "message_type": MESSAGE_TYPES.REQUESTED_BLOCKS, - # "data": self._msg_buffer[self._msg_offset:self._msg_len] - # }) - - case _: - raise InvalidJAMNPSMessage(f"Invalid JAMNPS message: {self._msg_type}") - finally: - self._reset_msg() - - # TODO: handle gracefully - # elif isinstance(event, ConnectionTerminated): - # # Handle connection termination - - async def open_stream_up_0(self): - # Initiate UP 0 stream by sending the - self.stream_up_0 = self._quic.get_next_available_stream_id() - self._quic.send_stream_data( - self.stream_up_0, - self.build_handshake_message(), - ) - logger.debug(f'ClientProtocol Block announcement stream opened') - - -class SessionTicketStore: - - def __init__(self) -> None: - self.tickets: Dict[bytes, SessionTicket] = {} - - def add(self, ticket: SessionTicket) -> None: - self.tickets[ticket.ticket] = ticket - - def pop(self, label: bytes) -> Optional[SessionTicket]: - return self.tickets.pop(label, None) - - -class JAMNPS(ProtocolType): - - class MSG(Enum): - UP0_OPEN: int = 66 - UP0_BlockAnnouncement: int = 0 - CE128_BlockRequest: int = 128 - - #TODO: 00000000 -> vervang met de eerste 8 nibbles vd genesis header hash op __init__ - PROTOCOL_NAME = "jamnp-s/0/00000000" - - # (host, port, certificate_file, pk_file, app, 0, "0259fbe9b7dd6f3ce7d7027d87453e886bf39ea902b7bae59af1d3c63b2db4ec") - def __init__(self, host, port, certificate, private_key, app): - self.host = host - self.port = port - self.broadcaster = app.pubsub - self.app = app - self.session_ticket_store = SessionTicketStore() - self.configuration = QuicConfiguration( - alpn_protocols=[JAMNPS.PROTOCOL_NAME], - is_client=False, - #quic_logger=quic_logger, - #verify_mode=ssl.CERT_REQUIRED - verify_mode=ssl.CERT_NONE, - idle_timeout=300000 - ) - self.cert = certificate - self.pk = private_key - self.configuration.load_cert_chain(certificate, private_key) - self.conn_in = {} # All incomming connections - self.conn_out = {} # All outgoing connections (who we connect to) - - - async def listen(self): - logger.debug(f'Listening on {self.host}:{self.port}') - await serve( - self.host, - self.port, - configuration=self.configuration, - create_protocol=wrap_protocol(self, ServerProtocol), - session_ticket_fetcher=self.session_ticket_store.pop, - session_ticket_handler=self.session_ticket_store.add, - retry=True, - ) - - async def connect(self, host, port): - configuration = QuicConfiguration( - alpn_protocols=[JAMNPS.PROTOCOL_NAME], - is_client=True, - #verify_mode=ssl.CERT_REQUIRED - verify_mode=ssl.CERT_NONE, - idle_timeout=300000 - ) - configuration.load_cert_chain(certfile=self.cert, keyfile=self.pk) - - logger.debug(f"ClientProtocol Connecting to {host}:{port}") - try: - async with connect( - host, - port, - configuration=configuration, - # session_ticket_handler=save_session_ticket, - create_protocol=wrap_protocol(self, ClientProtocol), - ) as client: - client = cast(ClientProtocol, client) - self.conn_out[(host, port)] = client - await client.open_stream_up_0() - await client.wait_closed() - del self.conn_out[(host, port)] - except ConnectionError: - if (host, port) in self.conn_out: - del self.conn_out[(host, port)] - logger.debug(f"💩 ClientProtocol Cannot connect to {host}:{port}") - - - async def request_blocks(self, direction, max_blocks, block_bytes): - #TODO: temp hack, should be provided with a specific peer? - conn_key = list(self.conn_out.keys())[0] - conn = self.conn_out[conn_key] - await conn.send_blocks_request(0, 100, block_bytes) - - - async def broadcast_block(self, block): - block_bytes = block.to_jam_bytes().to_bytes() - logger.debug(f'ServerProtocol broadcasting block announcement to {len(self.conn_in)} clients') - for client_id, client in self.conn_in.items(): - logger.debug(f"ServerProtocol send block to client {client}") - await client.send_block_announcement(block_bytes) diff --git a/pyjamaz/transport/rpc/blaas_playbook.py b/pyjamaz/transport/rpc/blaas_playbook.py new file mode 100644 index 00000000..65102132 --- /dev/null +++ b/pyjamaz/transport/rpc/blaas_playbook.py @@ -0,0 +1,301 @@ +import asyncio +from typing import List + +from pyjamaz.hashing import blake2b_256_hash +from pyjamaz.models.builder import Instruction +from pyjamaz.models.common import Authorizer, RefinementContext, WorkPackage, WorkItem, WorkItemExtrinsic +from pyjamaz.pvm.types import PVMProgram +from pyjamaz.transport.rpc.ws_client import WebsocketClient + + +async def create_bootservice_workpackage(client, instruction: Instruction, extrinsic: List[bytes]): + best_block = await client.bestBlock() + block_hash = best_block["header_hash"] + block_timeslot = best_block["slot"] + # block_hash = best_block[0] + # block_timeslot = best_block[1] + + state_root = await client.stateRoot(block_hash) + beefy_root = await client.beefyRoot(block_hash) + + authorizer = Authorizer( + code_hash=bytes.fromhex('4c4e4f63481b4b2b4726611dee56d0d8d1a3e163808b3ef678ab25dfa7c32419'), + params=b'' + ) + + context = RefinementContext( + anchor=block_hash, + state_root=state_root, + beefy_root=beefy_root, + lookup_anchor=block_hash, + lookup_anchor_slot=block_timeslot, + prerequisites=[] + ) + + work_package = WorkPackage( + authorization=b'', + auth_code_host=0, + authorizer=authorizer, + context=context, + items=[ + WorkItem( + accumulate_gas_limit=10000000, + code_hash=bytes.fromhex('7d952fd5905548e08a9a7d8fca521139f7e2573a2207d6a6d0e706a13070487b'), + export_count=0, + extrinsic=[WorkItemExtrinsic.from_blob(e) for e in extrinsic], + import_segments=[], + payload=instruction.to_jam_bytes().to_bytes(), + refine_gas_limit=5000000000, + service=0 + ) + ] + ) + + return work_package + + + +async def main(): + + async with WebsocketClient("ws://127.0.0.1:19800") as client: + + bootstrap_service_id = 0 + + # Check storage item + #new_service_id = await client.serviceValue(bytes(32), bootstrap_service_id, b'created') + #services = await client.serviceValue(bytes(32), bootstrap_service_id, b'\x10service_registry') + #print(services) + + # created_key = blake2b_256_hash(int(bootstrap_service_id).to_bytes(length=4, byteorder="little") + b'created') + + create_instruction = Instruction.from_json( + { + 'CreateService': { + 'code_hash': '0x0b77f392fed2d02b19a885627ffc96123394881a44fbb535af31fc3ba8394a74', + 'code_len': 11, + 'endowment': 100000, + 'memo': '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + 'min_item_gas': 1000000, + 'min_memo_gas': 1000000, + 'registration': 'Arie' + } + } + ) + + # core_vm_child_blob = bytes.fromhex( + # "080200080000020000a0004348494c44204e4f524d206e3d206669625f6e5f323d20726573756c743d202861646472323d202861646472313d29206669625f6e5f313d2920726573756c743d4348494c442042415345206e3d4348494c44205752495445206f75745f616464726573733d00003078303030313032303330343035303630373038303931303131313231333134313531363137313831393230323132323233323432353236323732383239333033313332333333343335333633373338333934303431343234333434343534363437343834393530353135323533353435353536353735383539363036313632363336343635363636373638363937303731373237333734373537363737373837393830383138323833383438353836383738383839393039313932393339343935393639373938393900000000000000000100000000000d000000000000000d0001000000000009000000000000001e0001000000000008000000000000002e000100000000000a00000000000000260001000000000008000000000000003800010000000000090000000000000041000100000000000d00000000000000160001000000000008000000000000004e000100000000001800000000000000160001000000000008000000000000001e0000000000000018000000000000000800000000000000200000000000000026000000000000002e000000000000004b598638d6c56d349b10000027028e790300b700c2007601e401ff01cd02e8025e0379030e04a604c5059806bc06ef0619073e0745076f0725084b0852080709190acb0a1e0b3f0b820bae0bc30bec0b040c5e0c130dac0d0b0e1a0e5e0e288101951178ff7b108000808934849a10520a168499205209518077821080009511880028e708817b3309810095177f33025701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842817b3309810095177f33023701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a013309026487330868000150100475098210800095118800320000951178ff7b108000808934849a10520a1684992052095182778210800095118800282808827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a0133090264873308680001501008b6088210800095118800320000951100ff7b10f8007b15f0007b16e800491108ffef7b1710330a027b1a551702940048111c019517107b17403307067b174895171c7b17507b1a5833079801017b177049117802492190009517407b17800049218800029517d00095187050100a14048215d800821be0008216d00033070233083309645a33000c0a6401821708c86707532700f00e01330710000395770010018278c98709ab59f900c9680901827aab8af17b79330b01ab8ae928e40097770c140800e0fefe00000000c878087b182081887a182c140900f0fefe00000000c897077b173081777a173cbe87077a171c9517107b17703307067b177895182c7b1880007b1a88009518207b1890007b17980095183c7b18a0007b1aa8009518307b18b0007b17b80095171c7b17c0007b1ac80033073801017b1740491148064911609518707b1850491158069517d00095184050100e2b038215d800821be0008216d00033070233083309645a3300100a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0181171097770c83770000fffe7a17309517307b174082187b184895171c7b17507b18583307b801017b177049117802492190009518407b18800049218800029517d0009518705010129a028215d800821be0008216d00033070233083309645a3300140a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0180173081181c7a78801730330800108210f8008215f0008216e8009511000132009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101632821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086e82a70851077182a91051099e0082a8330200103304100003c8240701827ac86a05aca5c200955b0188bc01d8b20bd4cb0b520bb200827bababe57b75330c7b1318c95407957700107b17107b180864957b14501018b40354250010940082131882181033077b380828b10049130833070128a800330700103302100003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302100003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101a7cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b1620828a086475510a3582893307959b080182bcc8c70795aaff95bb10520af5828a18510a248299088e99887a1085aa01d4a909897ae0a90952090a3307330901284b977701015107415707746453330900103302100003c8920b0182bcc87c0aacca5b95a501885601d85905d4650552054c82b6abc6e77bbac9a209330a0010c8a90964352806330901017b177b1908491110641750101c030652072282171082180882197b57107b58087b5982103082152882162095113832000000008272330900f0952affefac9a2782770833091000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950102241018217c876067b56103307821018821510821608951120320064577b1864a864695010248cfc8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a550102811fe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950102a34c8560682177b7610013307821020821518821610951128320064a76458646964a550102c7ffb645a82551028c42844049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a87b10507b15487b16407b18987904330827330a6a0001532971027b330827951b3e3a090000037b1910491108f0d80033037b143300ffe0f505016472821710d6720798770b821908c09709c82906976930989932ca39099894119899108499fe07964c9cc86c0c97cc3198cc30c8a9097c967c9901c8ac0c7cc5017ccc78b9ff78b6fe78b50178bc9588fc95bbfcac20ac5417633697793098993296997b14989911969b9cc8b7079777319877309588fec8a7077c7b017c77951c19c88c0c78cb0178c764970155170a149588ff951919c889098377307897281c9777019588fec8a7077c79017c77951a19c88a0a78a90178a701951a19c88a0a9a8b273308680001821733095010321282105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208507c7638c94a0a7b19185a16019d005206aa007b1a1028a90082752082762864576468821a38821b305010346c013308015207bb00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b305010361901520767821740c95705955501019555ff5105c600826920330830821748b49001385107ec28435216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510627825920821748821840b490013a5107ed330801016487821060821558821650951168320082164864676458821918821a38821b3050103c89003308015207d8825a186467821820821928b4a0013e3308015207c38217109a777b17383306ff01821738c867075117ff42825920821748821840b49001409566015107e62837826a18821748821820821928b4a00142330801520782330882168217107a6730821708786738286fff821610821710d876082863ff821710d87608285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c00144821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b17503307d801017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307307b1710017b18207b19288259510917821a588217508258f882aa18b4a0014652074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49001485207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a0014a5207568257825908951830b490014c520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0014e5107083307012805330701821080008215788216709511880032008948921491225992242525214a45b224494a4a42942984884624498a48912c4992929210a522599224252521ca1442442322425288244912129108911011a9d22408b144969a2480a404909424491291884424221121912422212252a54908b1244b4d82242549484422444244a44a93106249969a9488882849924a922449a42c454900c934499a24952451842c9124512a89a44290942489902549925253842c4992949a282555244bb2d49429494a92a492244912294ba12480649a244d9294ca922449494a4a9914214b9224a5442a4b0a494a4a925e4412624996aa2429a594144a4a92aa4229492a4a4a85322949924412494922492491944492481249245352922265495255282549a224b59224499224952c4949a994569224594992a44e9292109290208225499224892449494a529248224992a4243592a492a4244d122a92a424494a42922425a564499224942449921049524948a424494a499244914a42924c24891449529924c92449244b92524942929248523289249194249154922449922449a14a2a452949aa24a94952441249928444a2922449499249499288244952224992aa9449924892a42a6592242511499244494a9292a44c4992484924499294545292944452238900" + # ) + # program = PVMProgram.from_serialized_bytes(core_vm_child_blob, b'', b'') + #core_vm_child_code = bytes.fromhex('27028e790300b700c2007601e401ff01cd02e8025e0379030e04a604c5059806bc06ef0619073e0745076f0725084b0852080709190acb0a1e0b3f0b820bae0bc30bec0b040c5e0c130dac0d0b0e1a0e5e0e288101951178ff7b108000808934849a10520a168499205209518077821080009511880028e708817b3309810095177f33025701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842817b3309810095177f33023701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a013309026487330868000150100475098210800095118800320000951178ff7b108000808934849a10520a1684992052095182778210800095118800282808827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a0133090264873308680001501008b6088210800095118800320000951100ff7b10f8007b15f0007b16e800491108ffef7b1710330a027b1a551702940048111c019517107b17403307067b174895171c7b17507b1a5833079801017b177049117802492190009517407b17800049218800029517d00095187050100a14048215d800821be0008216d00033070233083309645a33000c0a6401821708c86707532700f00e01330710000395770010018278c98709ab59f900c9680901827aab8af17b79330b01ab8ae928e40097770c140800e0fefe00000000c878087b182081887a182c140900f0fefe00000000c897077b173081777a173cbe87077a171c9517107b17703307067b177895182c7b1880007b1a88009518207b1890007b17980095183c7b18a0007b1aa8009518307b18b0007b17b80095171c7b17c0007b1ac80033073801017b1740491148064911609518707b1850491158069517d00095184050100e2b038215d800821be0008216d00033070233083309645a3300100a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0181171097770c83770000fffe7a17309517307b174082187b184895171c7b17507b18583307b801017b177049117802492190009518407b18800049218800029517d0009518705010129a028215d800821be0008216d00033070233083309645a3300140a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0180173081181c7a78801730330800108210f8008215f0008216e8009511000132009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101632821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086e82a70851077182a91051099e0082a8330200103304100003c8240701827ac86a05aca5c200955b0188bc01d8b20bd4cb0b520bb200827bababe57b75330c7b1318c95407957700107b17107b180864957b14501018b40354250010940082131882181033077b380828b10049130833070128a800330700103302100003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302100003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101a7cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b1620828a086475510a3582893307959b080182bcc8c70795aaff95bb10520af5828a18510a248299088e99887a1085aa01d4a909897ae0a90952090a3307330901284b977701015107415707746453330900103302100003c8920b0182bcc87c0aacca5b95a501885601d85905d4650552054c82b6abc6e77bbac9a209330a0010c8a90964352806330901017b177b1908491110641750101c030652072282171082180882197b57107b58087b5982103082152882162095113832000000008272330900f0952affefac9a2782770833091000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950102241018217c876067b56103307821018821510821608951120320064577b1864a864695010248cfc8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a550102811fe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950102a34c8560682177b7610013307821020821518821610951128320064a76458646964a550102c7ffb645a82551028c42844049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a87b10507b15487b16407b18987904330827330a6a0001532971027b330827951b3e3a090000037b1910491108f0d80033037b143300ffe0f505016472821710d6720798770b821908c09709c82906976930989932ca39099894119899108499fe07964c9cc86c0c97cc3198cc30c8a9097c967c9901c8ac0c7cc5017ccc78b9ff78b6fe78b50178bc9588fc95bbfcac20ac5417633697793098993296997b14989911969b9cc8b7079777319877309588fec8a7077c7b017c77951c19c88c0c78cb0178c764970155170a149588ff951919c889098377307897281c9777019588fec8a7077c79017c77951a19c88a0a78a90178a701951a19c88a0a9a8b273308680001821733095010321282105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208507c7638c94a0a7b19185a16019d005206aa007b1a1028a90082752082762864576468821a38821b305010346c013308015207bb00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b305010361901520767821740c95705955501019555ff5105c600826920330830821748b49001385107ec28435216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510627825920821748821840b490013a5107ed330801016487821060821558821650951168320082164864676458821918821a38821b3050103c89003308015207d8825a186467821820821928b4a0013e3308015207c38217109a777b17383306ff01821738c867075117ff42825920821748821840b49001409566015107e62837826a18821748821820821928b4a00142330801520782330882168217107a6730821708786738286fff821610821710d876082863ff821710d87608285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c00144821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b17503307d801017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307307b1710017b18207b19288259510917821a588217508258f882aa18b4a0014652074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49001485207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a0014a5207568257825908951830b490014c520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0014e5107083307012805330701821080008215788216709511880032008948921491225992242525214a45b224494a4a42942984884624498a48912c4992929210a522599224252521ca1442442322425288244912129108911011a9d22408b144969a2480a404909424491291884424221121912422212252a54908b1244b4d82242549484422444244a44a93106249969a9488882849924a922449a42c454900c934499a24952451842c9124512a89a44290942489902549925253842c4992949a282555244bb2d49429494a92a492244912294ba12480649a244d9294ca922449494a4a9914214b9224a5442a4b0a494a4a925e4412624996aa2429a594144a4a92aa4229492a4a4a85322949924412494922492491944492481249245352922265495255282549a224b59224499224952c4949a994569224594992a44e9292109290208225499224892449494a529248224992a4243592a492a4244d122a92a424494a42922425a564499224942449921049524948a424494a499244914a42924c24891449529924c92449244b92524942929248523289249194249154922449922449a14a2a452949aa24a94952441249928444a2922449499249499288244952224992aa9449924892a42a6592242511499244494a9292a44c4992484924499294545292944452238900') + + #TODO: + # with open("/Users/matthijsblaas/dev/polkavm/services/corevm_child/corevm_child.pvm", "rb") as ff: + # core_vm_child_blob = ff.read() + # program = PVMProgram.from_serialized_bytes(core_vm_child_blob, b'', b'') + # core_vm_child_code = program.code + # core_vm_child_code = program._code #bytes.fromhex("20028b8d0300b50043015e01e6017e029d03cb03fe0328044d0454047e0434055a05610516062d07df07320853089608c208d708000918097209270ac00a1f0b2e0b720b28c000951178ff7b108000808934849a10520a1484992052094f821080009511880028f805827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a01330902648733080800015010048b068210800095118800320000951178ff7b1080007b15787b16707b17089517087b17403307027b17483307d800017b1710491118014911309518407b182049112801330700103306100003c8760801828a95a910aca99300959b0188bc01d8b70bd4cb0b520b8300828bababe57b89330c7b16c9960795770010491150107b17584911609517509518105010066c08520759821558821b6082165033070233083309645a3300080a64019568ffef532800f022821895870010018278c98709ab5911c9680901827aab8af27b79330b01821708330800108210800082157882167095118800320000009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950100a32821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086e82a70851077182a91051099e0082a8330200103304100003c8240701827ac86a05aca5c200955b0188bc01d8b20bd4cb0b520bb200827bababe57b75330c7b1318c95407957700107b17107b180864957b1450100ceb0254250010940082131882181033077b380828b10049130833070128a800330700103302100003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302100003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950100e7cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200008272330900f0952affefac9a2782770833091000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950101441018217c876067b56103307821018821510821608951120320064577b1864a8646950101655fd8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a550101adafe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950101c34c8560682177b7610013307821020821518821610951128320064a76458646964a550101e48fc645a82551028c42849049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a87b10507b15487b1640827a7b1898ab0433082733090a0001532b71027e330827951b3e3a070000037b1710491108f0d80033007b143303ffe0f50533059c0164a4821710d67a0a98aa0b821708c07a0cc84c06976c3098cc32ca0c0c98c71198cc1084ccfe07ca5707c86707977731987730c89c0c7cc67ccc01c897077c72017c7778bcff78b6fe78b20178b79588fc95bbfcac43ac541a633697a73098773296777b14987711967b9cc8ba0a97aa3198aa309588fec89a0a7cab017caa951c19c88c0c78cb0178ca647a01551a0a149588ff951719c8870783a9307879281c97aa019588fec8a9097c97017c99951a19c88a0a78a70178a901951a19c88a0a9a8b273308080001821733095010241282105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208507c7638c94a0a7b19185a16019d005206aa007b1a1028a90082752082762864576468821a38821b305010266c013308015207bb00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b305010281901520767821740c95705955501019555ff5105c600826920330830821748b490012a5107ec28435216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510627825920821748821840b490012c5107ed330801016487821060821558821650951168320082164864676458821918821a38821b3050102e89003308015207d8825a186467821820821928b4a001303308015207c38217109a777b17383306ff01821738c867075117ff42825920821748821840b49001329566015107e62837826a18821748821820821928b4a00134330801520782330882168217107a6730821708786738286fff821610821710d876082863ff821710d87608285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c00136821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b17503307e800017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307227b1710017b18207b19288259510917821a588217508258f882aa18b4a0013852074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b490013a5207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a0013c5207568257825908951830b490013e520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0014051070833070128053307018210800082157882167095118800320089489244a44896244949498852912c4992929210650a21a211499224249244842c912451aa44244948925469846249969a88243a49924a922449a42c454900c934499a24952451842c9124512a89a44290942489902549925253842c4992949a282555244bb2d49429494a92a492244912294ba12480649a242d2209b1244b559294524a0a25254955a194241525a542999424492289a424912492484a22492489249229294991b224a92a94922451925a49922449924a96a4a4544a2b4992ac24495227492521242141045992244992489294a4242589249224494a5223492a494ad224a122494a92a424244952524a962449424992240991249584444a92a494244914a92424c944924891249549924c9244b22429952424298924259348124949124925499224499214aaa4529492a44a929a24452491244948242a4992942499942489489224259224a94a9924892449aa522649521291244994a4242949ca9424899444922449492525494924359208") + # rom = program._rom #bytes.fromhex('4348494c44206e3d3078303030313032303330343035303630373038303931303131313231333134313531363137313831393230323132323233323432353236323732383239333033313332333333343335333633373338333934303431343234333434343534363437343834393530353135323533353435353536353735383539363036313632363336343635363636373638363937303731373237333734373537363737373837393830383138323833383438353836383738383839393039313932393339343935393639373938393900000000000000000100000000000800000000000000100000000000000018000000000000000800000000000000120000000000000018000000000000002000000000000000') + # ram = program._ram #bytearray(b'KY\x868\xd6\xc5m4') + + core_vm_child_code = bytes(bytearray([0, 0, 33, 51, 8, 1, 51, 9, 1, 40, 3, 0, 149, 119, 255, 81, 7, 12, 100, 138, 200, 152, 8, 100, 169, 40, 243, + 100, 135, 51, 8, 51, 9, 1, 50, 0, 73, 147, 82, 213, 0])) + rom = bytes(4096) + ram = bytes(4096) + + extrinsic = [core_vm_child_code, rom, ram] + # extrinsic = [] + + work_package = await create_bootservice_workpackage(client, create_instruction, extrinsic) + # work_package = await create_bootservice_workpackage(client, create_instruction, []) + + await client.submitWorkPackage(0, work_package, extrinsic) + print("WORKPACKAGE SUBMITTED") + + new_service = await client.subscribeServiceValue(bootstrap_service_id, b'created') + async for data in new_service: + print("SUBSCRIPTION RECEIVED DATA", data) + if data: + new_service_id = int.from_bytes(data, byteorder='little') + print(new_service_id) + break + + + """ + + bootstrap_service_id = 0 + + # Check storage item + new_service_id = await client.serviceValue(bytes(32), bootstrap_service_id, b'created') + services = await client.serviceValue(bytes(32), bootstrap_service_id, b'\x10service_registry') + print(services) + + create_instruction = Instruction.from_json( + { + 'CreateService': { + 'code_hash': '0x0b77f392fed2d02b19a885627ffc96123394881a44fbb535af31fc3ba8394a74', + 'code_len': 11, + 'endowment': 100000, + 'memo': '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + 'min_item_gas': 1000000, + 'min_memo_gas': 1000000, + 'registration': 'Arie' + } + } + ) + + transfer_instruction = Instruction.from_json({'Transfer': { + 'destination': 3081892978, + 'amount': 66666666, + 'gas_limit': 1000000, + 'memo': '0x0102030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + }}) + + random_storage_instruction = Instruction.from_json({'RandomStorageRefine': { + 'seed': 3081892978, + 'nb_items': 6 + }}) + + export_instruction = Instruction.from_json( + {'Export': { + 'data': [b'test'], + }} + ) + + zombify_instruction = Instruction.from_json({'Zombify': {'ejector': 0}}) + + eject_instruction = Instruction.from_json({'Eject': {'target': 0, 'code_hash': '0x6c63e601e26279872a93b9b443aa52ad1c26e795647f63c0b7e0abff0d3680da'}}) + + core_vm_child_blob = bytes.fromhex("080200080000020000a0004348494c44204e4f524d206e3d206669625f6e5f323d20726573756c743d202861646472323d202861646472313d29206669625f6e5f313d2920726573756c743d4348494c442042415345206e3d4348494c44205752495445206f75745f616464726573733d00003078303030313032303330343035303630373038303931303131313231333134313531363137313831393230323132323233323432353236323732383239333033313332333333343335333633373338333934303431343234333434343534363437343834393530353135323533353435353536353735383539363036313632363336343635363636373638363937303731373237333734373537363737373837393830383138323833383438353836383738383839393039313932393339343935393639373938393900000000000000000100000000000d000000000000000d0001000000000009000000000000001e0001000000000008000000000000002e000100000000000a00000000000000260001000000000008000000000000003800010000000000090000000000000041000100000000000d00000000000000160001000000000008000000000000004e000100000000001800000000000000160001000000000008000000000000001e0000000000000018000000000000000800000000000000200000000000000026000000000000002e000000000000004b598638d6c56d349b10000027028e790300b700c2007601e401ff01cd02e8025e0379030e04a604c5059806bc06ef0619073e0745076f0725084b0852080709190acb0a1e0b3f0b820bae0bc30bec0b040c5e0c130dac0d0b0e1a0e5e0e288101951178ff7b108000808934849a10520a168499205209518077821080009511880028e708817b3309810095177f33025701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842817b3309810095177f33023701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a013309026487330868000150100475098210800095118800320000951178ff7b108000808934849a10520a1684992052095182778210800095118800282808827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a0133090264873308680001501008b6088210800095118800320000951100ff7b10f8007b15f0007b16e800491108ffef7b1710330a027b1a551702940048111c019517107b17403307067b174895171c7b17507b1a5833079801017b177049117802492190009517407b17800049218800029517d00095187050100a14048215d800821be0008216d00033070233083309645a33000c0a6401821708c86707532700f00e01330710000395770010018278c98709ab59f900c9680901827aab8af17b79330b01ab8ae928e40097770c140800e0fefe00000000c878087b182081887a182c140900f0fefe00000000c897077b173081777a173cbe87077a171c9517107b17703307067b177895182c7b1880007b1a88009518207b1890007b17980095183c7b18a0007b1aa8009518307b18b0007b17b80095171c7b17c0007b1ac80033073801017b1740491148064911609518707b1850491158069517d00095184050100e2b038215d800821be0008216d00033070233083309645a3300100a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0181171097770c83770000fffe7a17309517307b174082187b184895171c7b17507b18583307b801017b177049117802492190009518407b18800049218800029517d0009518705010129a028215d800821be0008216d00033070233083309645a3300140a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0180173081181c7a78801730330800108210f8008215f0008216e8009511000132009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101632821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086e82a70851077182a91051099e0082a8330200103304100003c8240701827ac86a05aca5c200955b0188bc01d8b20bd4cb0b520bb200827bababe57b75330c7b1318c95407957700107b17107b180864957b14501018b40354250010940082131882181033077b380828b10049130833070128a800330700103302100003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302100003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101a7cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b1620828a086475510a3582893307959b080182bcc8c70795aaff95bb10520af5828a18510a248299088e99887a1085aa01d4a909897ae0a90952090a3307330901284b977701015107415707746453330900103302100003c8920b0182bcc87c0aacca5b95a501885601d85905d4650552054c82b6abc6e77bbac9a209330a0010c8a90964352806330901017b177b1908491110641750101c030652072282171082180882197b57107b58087b5982103082152882162095113832000000008272330900f0952affefac9a2782770833091000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950102241018217c876067b56103307821018821510821608951120320064577b1864a864695010248cfc8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a550102811fe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950102a34c8560682177b7610013307821020821518821610951128320064a76458646964a550102c7ffb645a82551028c42844049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a87b10507b15487b16407b18987904330827330a6a0001532971027b330827951b3e3a090000037b1910491108f0d80033037b143300ffe0f505016472821710d6720798770b821908c09709c82906976930989932ca39099894119899108499fe07964c9cc86c0c97cc3198cc30c8a9097c967c9901c8ac0c7cc5017ccc78b9ff78b6fe78b50178bc9588fc95bbfcac20ac5417633697793098993296997b14989911969b9cc8b7079777319877309588fec8a7077c7b017c77951c19c88c0c78cb0178c764970155170a149588ff951919c889098377307897281c9777019588fec8a7077c79017c77951a19c88a0a78a90178a701951a19c88a0a9a8b273308680001821733095010321282105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208507c7638c94a0a7b19185a16019d005206aa007b1a1028a90082752082762864576468821a38821b305010346c013308015207bb00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b305010361901520767821740c95705955501019555ff5105c600826920330830821748b49001385107ec28435216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510627825920821748821840b490013a5107ed330801016487821060821558821650951168320082164864676458821918821a38821b3050103c89003308015207d8825a186467821820821928b4a0013e3308015207c38217109a777b17383306ff01821738c867075117ff42825920821748821840b49001409566015107e62837826a18821748821820821928b4a00142330801520782330882168217107a6730821708786738286fff821610821710d876082863ff821710d87608285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c00144821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b17503307d801017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307307b1710017b18207b19288259510917821a588217508258f882aa18b4a0014652074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49001485207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a0014a5207568257825908951830b490014c520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0014e5107083307012805330701821080008215788216709511880032008948921491225992242525214a45b224494a4a42942984884624498a48912c4992929210a522599224252521ca1442442322425288244912129108911011a9d22408b144969a2480a404909424491291884424221121912422212252a54908b1244b4d82242549484422444244a44a93106249969a9488882849924a922449a42c454900c934499a24952451842c9124512a89a44290942489902549925253842c4992949a282555244bb2d49429494a92a492244912294ba12480649a244d9294ca922449494a4a9914214b9224a5442a4b0a494a4a925e4412624996aa2429a594144a4a92aa4229492a4a4a85322949924412494922492491944492481249245352922265495255282549a224b59224499224952c4949a994569224594992a44e9292109290208225499224892449494a529248224992a4243592a492a4244d122a92a424494a42922425a564499224942449921049524948a424494a499244914a42924c24891449529924c92449244b92524942929248523289249194249154922449922449a14a2a452949aa24a94952441249928444a2922449499249499288244952224992aa9449924892a42a6592242511499244494a9292a44c4992484924499294545292944452238900") + + extrinsic = [core_vm_child_blob] + + work_package = await create_bootservice_workpackage(client, create_instruction, extrinsic) + + await client.submitWorkPackage(0, work_package, extrinsic) + print("Workpackage submitted") + exit() + + # block_hash = work_package.context.anchor + # + # core_vm_blob = bytes.fromhex("06636f7265766d481200180000020000a0008c00ffffa400ffffb600ffffc800ffffe000fffff800ffff0e01ffff1a01ffff2601ffff3801ffff0010000000000000fcfffffffffffffffaffffffffffffff657870756e6765200000000000000000ffffffffffffffff206f75747075743df7ffffffffffffff7a3d20733d206f5f62797465735f616464726573733d20635f62797465735f6c656e6774683d696e666f3a20657870656374204f4b20206f5f62797465735f6c656e6774683d20775f62797465735f6c656e6774683d3a2065787065637420cf822b7c657c3d3a20696e7365727420742c20676f74207969656c642c20657870656374204f4b20775f62797465735f616464726573733d20635f62797465735f616464726573733d6761735f726573756c743d6d616368696e65206e657720696e6465783d6665746368207365676d656e745f696e6465783d2066657463685f726573756c743d7a65726f206d3d2c20706167655f69643d207a65726f5f726573756c743d706f6b65206d3d206f3d207a3d20706f6b655f726573756c743d7a65726f20666f7220726573756c74206d3d6265666f7265206368696c645f766d5f7265676973746572733d696e766f6b652020696e766f6b655f726573756c743d206761733d6f75747075745f62797465733d7c3a206368696c6420564d20696e737472756374696f6e20636f756e7465723d7065656b206368696c645f766d5f69643d2c207365676d656e745f6275665f706167655f616464726573733d2c206368696c645f706167655f616464726573733d20504147455f53495a453d207065656b5f726573756c743d207365676d656e745f6275665b302e2e385d3d2c206368696c645f69643d2c207365675f696e6465783d6578706f727420693d2c20676f7420726561642066726f6d206a616d3a20657870656374204e4f4e452020287265636f72646564206174206b6579203129777269746520746f206a616d3a20657870656374204e4f4e452020287265636f72646564206174206b6579203229726561642066726f6d206a616d3a20657870656374204f4b2020287265636f72646564206174206b6579203529666f72676574206a616d3a20657870656374204855482020287265636f72646564206174206b657920362972656164206a616d3a20657870656374204f4b2077726974652064656c65746564206a616d3a206578706563742070726576206c656e20332c20676f742072656164206a616d3a20657870656374204e4f4e4520736f6c696369742068617368286a616d293a20657870656374204f4b2071756572792068617368286a616d293a20657870656374206e6f6e2d5a45524f2c20676f74207175657279206861736828646f74293a20657870656374204e4f4e4520666f726765742068617368286a616d293a20657870656374204f4b2071756572792068617368286a616d293a20657870656374206e6f6e2d7a65726f2c20676f74206c6f6f6b7570206861736828646f74293a20657870656374204e4f4e452061737369676e206a616d3a2065787065637420434f5245206c6f6f6b75702068617368286a616d293a20657870656374204f4b2071756572792068617368286a616d293a20657870656374204f4b20656a6563743a206578706563742057484f20626c6573733a206578706563742057484f20736f6c696369742068617368286a616d292c20657870656374204f4b2061737369676e3a20657870656374204f4b202028322b325e33322a78292c20676f74206c6f6f6b75702068617368286a616d292c20657870656374204f4b203a20332028322b325e33322a78292c20676f74206e65773a20657870656374204f4b202028736572766963655f696e646578292c20676f7420757067726164653a20657870656374204f4b20626c6573733a20657870656374204f4b2077726974652064656c6574656420444f543a20657870656374204e4f4e4520777269746520746f20444f543a20657870656374204e4f4e452077726974652064656c6574656420444f543a206578706563742070726576206c656e20332c20676f7420726561642066726f6d20444f543a20657870656374204e4f4e452020287265636f72646564206174206b657920372920287265636f72646564206174206b65792038296761733a20676f742020287265636f72646564206174206b6579203929636f7265766d20636865636b706f696e746f6e5f7472616e73666572206761733a20676f742020287265636f72646564206174206b6579203429005b696e666f726561647065656b7a65726f20202020706f6b652c202c0a0a5d307830303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839395374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20737563636573735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f72206f5f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220737461636b5374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f72206f5f627974657377726974655f726573756c74206b65793d2c20726573756c743d000000680001000000000002000000000000006a0001000000000003000000000000006d0001000000000011000000000000009e000100000000001000000000000000ee000100000000001100000000000000ae000100000000001000000000000000ff0001000000000011000000000000007e00010000000000100000000000000010010100000000000b000000000000001b0101000000000012000000000000002d01010000000000140000000000000041010100000000000e000000000000004f01010000000000070000000000000056010100000000000a0000000000000060010100000000000d000000000000006d0101000000000007000000000000006a00010000000000030000000000000074010100000000000300000000000000770101000000000003000000000000007a010100000000000d000000000000008701010000000000120000000000000056010100000000000a0000000000000060010100000000000d0000000000000099010100000000001a00000000000000b3010100000000000700000000000000ba010100000000000f00000000000000c9010100000000000500000000000000ce010100000000000d00000000000000db010100000000000100000000000000db01010000000000010000000000000040000100000000000800000000000000dc010100000000001f00000000000000c9010100000000000500000000000000fb0101000000000011000000000000000c020100000000001b00000000000000270201000000000015000000000000003c020100000000000b0000000000000047020100000000000d000000000000005402010000000000130000000000000067020100000000000b0000000000000072020100000000000c000000000000007e020100000000000900000000000000be00010000000000100000000000000087020100000000000600000000000000c9010100000000000500000000000000580001000000000008000000000000008d020100000000001b0000000000000087020100000000000600000000000000a8020100000000001400000000000000bc020100000000001a0000000000000087020100000000000600000000000000d6020100000000001400000000000000ea020100000000001900000000000000870201000000000006000000000000000303010000000000140000000000000017030100000000001700000000000000870201000000000006000000000000002e0301000000000014000000000000004203010000000000140000000000000087020100000000000600000000000000a802010000000000140000000000000056030100000000002a00000000000000d602010000000000140000000000000080030100000000001600000000000000870201000000000006000000000000000303010000000000140000000000000096030100000000001d0000000000000087020100000000000600000000000000a8020100000000001400000000000000b3030100000000002600000000000000d6020100000000001400000000000000d9030100000000001d000000000000008702010000000000060000000000000003030100000000001400000000000000f6030100000000001c0000000000000087020100000000000600000000000000a802010000000000140000000000000012040100000000002600000000000000d602010000000000140000000000000038040100000000001e00000000000000870201000000000006000000000000000303010000000000140000000000000056040100000000001800000000000000870201000000000006000000000000002e0301000000000014000000000000006e040100000000001c0000000000000087020100000000000600000000000000a80201000000000014000000000000008a040100000000001b0000000000000087020100000000000600000000000000d6020100000000001400000000000000a50401000000000012000000000000008702010000000000060000000000000003030100000000001400000000000000b7040100000000001200000000000000870201000000000006000000000000002e030100000000001400000000000000c9040100000000001d00000000000000ce000100000000001000000000000000a8020100000000001400000000000000e604010000000000120000000000000087020100000000000600000000000000030301000000000014000000000000008a040100000000001b00000000000000f8040100000000001100000000000000a802010000000000140000000000000009050100000000001c0000000000000025050100000000001400000000000000a80201000000000014000000000000008a040100000000001b00000000000000f8040100000000001100000000000000d602010000000000140000000000000039050100000000000f0000000000000048050100000000001600000000000000a80201000000000014000000000000005e05010000000000130000000000000087020100000000000600000000000000d602010000000000140000000000000071050100000000001100000000000000870201000000000006000000000000000303010000000000140000000000000082050100000000001f0000000000000087020100000000000600000000000000a8020100000000001400000000000000a1050100000000001a0000000000000087020100000000000600000000000000a8020100000000001400000000000000bb050100000000002a0000000000000003030100000000001400000000000000e5050100000000001b00000000000000870201000000000006000000000000002e03010000000000140000000000000082050100000000001f0000000000000087020100000000000600000000000000000601000000000014000000000000008e00010000000000100000000000000087020100000000000600000000000000140601000000000014000000000000002806010000000000090000000000000031060100000000001400000000000000560601000000000015000000000000006b06010000000000140000000000000076010000000000001800000000000000080000000000000078010000000000007e010000000000008601000000000000a80100000000000018000000000000000800000000000000aa01000000000000b001000000000000b401000000000000cb080100000000001100000000000000dc08010000000000090000000000000056555555555555554b598638d6c56d348080808080808080604e000080e502c00e440d00c500d000f90024014f01620118022302d902e4029803a303570462048904a404b604c804da04ec04fe04100522053405460558056a057c059c0524067f061d083808a908c40836095109bc0a710b8d0b240c3c0cf40c0c0dae0dca0d710e8c0e940fb30f01104f10cc10eb1022124112ed120813e31302148814a714371553152f1698163f170c193919a519c619031a631a7c1abc1a231b3c1b7a1bcc1be51b181c7c1c9d1cdd1c321d4b1d8c1deb1d041e371e8e1eaf1eef1e401f591f9a1fec1f052042209920ba20fa204a216321a321082221225f22b322cc22ff225f238023bd23172430247024cf24e824262584259d25da25ee253a265b26ea260e274e275e277027db27f32726287e289f28dd282e2947297a29db29fc293a2a8b2aa42ae12a402b612b9e2bfd2b162c562cc92ce22c212d842da52de82d482e612e9f2ef32e0c2f472faf2fc82f043059307230ac30c630123133317331b131ca31183254328e32be32d7325f33f8331835f03514364736723698369f36ca368137a837af37c838db398e3ae23a043b483b753b8b3bb53bce3b2a3cda3c743dd73de73d2c3e473e493ec63e0a4053408340b9402f4149417441dd41f641484361439e43c643df43004428aa050000288b150000286c32951178ff7b1080008089348277849a10520a168499205209527c778210800095118800289c387c77330b810095197f3302570164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe562780006a9abb8100641ac87a0a28437c77330b810095197f3302370164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe56278000289abb8100641ac87a0a01330902648733089f0601501004293982108000951188003200009511c07b10387b15307b16287b18088289288276827508828720829a183308800601330901b4a001088218087b181078171846111951052c3307027b17019567017b17087b1620951710951820821950100aa63f9555ff8216085205e47c17180133080152071e821710827828827720828a1833089e0601330901b4a0010c64780164878210388215308216289511403200951178ff7b1080008089348277849a10520a1684992052095182778210800095118800284737827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a01330902648733089f0601501010d6378210800095118800320000951178ff7b108000808934849a10520a168499205209527c7782108000951188002888367c77330b810095197f3302570164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe562780006a9abb8100641ac87a0a28437c77330b810095197f3302370164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe56278000289abb8100641ac87a0a01330902648733089f060150101415378210800095118800320000951178ff7b108000808934849a10520a168499205209518077821080009511880028c735817b3309810095177f33025701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842817b3309810095177f33023701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a01330902648733089f060150101856368210800095118800320000951178ff7b108000808934849a10520a1684992052095182778210800095118800280835827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a01330902648733089f060150101c973582108000951188003200009511d07b10287b15207b16186485828828825a20828b186476330880060133090164a7b4b001207b157817084611097b161033050e641795181033090e501022263c9567087b171064179518106459501024143c9567107b171064179518106459501026023c9567187b171064179518106459501028f03b9567207b17106417951810645950102ade3b9567287b17106417951810645950102ccc3b9567307b17106417951810645950102eba3b9567387b171064179518106459501030a83b9567407b171064179518106459501032963b9567487b171064179518106459501034843b9567507b171064179518106459501036723b9567587b171064179518106459501038603b9567607b17106417951810645950103a4e3b3307017c180852081a8217827828827720828a1833089e0601330901b4a0013c8210288215208216189511303200951108f87b10f0077b15e8077b16e007951148d4330a000001531804df00958bfc510bd7007d7804807a33060159083d8488ff003306025328c0002d3306035328e000253306045328f0001d3306055328f800153306065328fc000d8888fe009a860801ae6b06287e0f7b1a6895770464687b1b7050103ee53b6475821770e46707c96707d85708e45707c95707887720d4870752075b48219800492190004921880049218000491178951778330924330a033308330b330c0a1201951a78330824531508399517a000330900203308501040f3319518789519a000330b0020821768330a0a11019578015518042b3308330a000001280533080164a73309b82bc891018210f0078215e8078216e0079511f80732009578fd531803d68478fe511806cf9578f8531803c87c18a2007c19a1007c1aa000978810979908d49808d4a8089579f5ac89a97c17a5007c1aa4007c1ba30097771097aa08d4a707d4b707c98909ac798bc97906531604859512ab00c82803c8370b7cbc037cb5027cba7cb90197cc10975508d45c0cd4c909979908d4a90c9566fcacc657ff7c19a700951aa0207c14a6009799087c16aa007c15a900d449047c19a800976610975508d46505d459093305ffef7b157095bb047ba47ba9087ba2107ba8187ba3207ba7287bab307bac387baa5033081a7ba8589517a8207ba7607ba8689517b0207ba7707ba8789517b8207ba780007ba888009517c0207ba790007ba898009517c8207ba7a0007ba8a8009517d0207ba7b0007ba8b8009517d8207ba7c0007b18687ba8c8003307e808019516f8307b6748014926500108492668019518f0207b685801492660010895178831951840325010422e2d82659800826ba0008266900033070233083309645a3300440a6401821770c86707330c400003532700f01e95c70010018278c98709ab590fc9680901827aab8af27b79017b1c600a9518a0207b87409517e0209516f8307b6790008217687b67980033076809017b17187b8750951788317b87604918580149187049186801951740329518f020501046a22c82655001826b58018266480133070233083309645a3300480a6401821770c86707532700f02182186095870010018278c98709ab590fc9680901827aab8af27b79019515a02082573082583833090a147b57489517e8209516f8307b67900033077809017b5750951788317b576049155801491568018217687b679800491570951740329518f02050104a152c82655001826b58018266480133070233083309645a33004c0a6401821770c86707532700f02182186095870010018278c98709ab590fc9680901827aab8af27b79019519a02082977b17488297087b17408297107b17388295188298207b1830809748829628491150ff0f9559ff0f98990c3308107b17580a1701510717330a8d0801330702330b3e330833090a6428e0007b1628821750c8670798770c821948c879097b15489557ffff0084770000ff957500000298580c8217580a1701510717330a4f0801330702330b3e330833090a64289c00821650821740c8760698690c846700f014080000fefe00000000c9780898880c8217580a1701510716330a130801330702330b3c330833090a64285f3309000001821758821838821a480a1601510716330ad50701330702330b3e330833090a6428388217588218306459821a280a1601510716330a970701330702330b3e330833090a642814330a690701330702330b2e330833090a64019516f830330508109517f02033083309081050104eb62d49069517f8207b67084916104916189517f020330a0633087b15586459330b330c0a12017b67680233082800017b18505117ff530233078809017b17483307a809017b17403307d809017b173828279516f830826b95bb017b6b9517f020330a063308821958330c0a12017b6768025117ff14027b6690008217687b679800951860337b68a0007b67a8008217487b674801492650010249266801951888317b68580149266001029517203195184032501050da299517f830827630827b3882752833070233083309646a3300520a6401821770c85707821c6033020010532700f01cc82c088287c97809ab690fc9570901828aab7aef7b89019518a0208087508088549515f8307b57107b58183309010a177b574802951708317b5748018217687b575001951810317b5858017b576001951840337b5868017b5770018217407b57900049259800034925b000951740327b57a0004925a8000395172031951888315010542729825630825b3882552833070233083309646a3300560a640133020010821c60821770c85707532700f01cc82c088287c97809ab690fc9570901828aab7aef7b89019515f8308259188257109518f0207b58780297990c7b598802330a00109518f8200a167b570801951708317b5748018217687b575001951870337b5858017b576001951880337b5868017b5770018218507b5878017b578001951800327b5888017b5790018217387b57900049259800054925b000951740327b57a0004925a8000595172031951888315010585728825630825b3882552833070233083309646a33005a0a640133020010821c60821770c85707532700f0f2fdc82c088287c97809ab69e4fdc9570901828aab7aee7b89330b01ab7ae628cffd826918959a018267103308f0ef0fdb9a087b68183309010a177b6720951708317b674801951710317b675801951718317b6768013307280a017b679000951740327b67a00049269800034926a800038217687b6750017b6760017b6770014926b000951720319518883150105c9d27826530826b389517f83082762833070233083309645a33005e0a6401821770c86707532700f02382186095870010018278c98709ab5911c9680901827aab8af27b79330b019516f83049165849165049164849164049163849167049167814070000ffff000000007b672814070000fefe000000007b6730826749268000492688004916687b6760951720317b67080133071e7b6710013307580a017b674801492650010149266801951700327b67580149266001019517883195184032501060da2682659800826ba0008266900033070233083309645a3300620a6401821770c86707821360532700f01e95370010018278c98709ab590fc9680901827aab8af27b7901951cf83082c72882c83082c93882ca4082cb4882c25082c658492c900000000182c5607bc7980082c7687bc8a00082c8707bc9a80082c9787bcab00082ca80007bcbb80082cb88007bc2c0007bc6c8009516f8307b65d0007b67d8007b68e0007b69e8007b6af0007b6bf8003307680a017b1748953700107b1740019517a020827748951888310a197b18587b6700019517e8207b6748018217687b6750019518f8317b6858017b6760019518e0207b6868017b6770018217487b670801492610010349262801951740327b67180149262001039517803395180032501064b72582659002826b98029517f8308276880233070233083309645a3300660a6401821770c86707821b40532700f01982b7c97b08ab580fc967080182b9ab79f27bb8019516f830826700015107ae00857703821858858864d48707520742ff9517203133096895189031501068bf278267607b17588267687b17288265707b15208267787b1738826780007b173049264001492638014926300149262801492620014926180149261001492608019517403233090001330850106a23289517a02082774895180032821928645a0a159517a02082774895184032821938821530645a0a1595180032951a4032821758821920645b0a6428a7fe0a9518a0207b87409517e0207b6788028217187b674801951780337b675801492650010149266001018217687b67900249266801951700329518403250106c7f2482651001826b18019517f8308276080133070233083309645a33006e0a6401821770c86707532700f02382186095870010018278c98709ab5911c9680901827aab8af27b79330b019517a0208277489516f830482650024926480282697a6754023308127b18487b19405119ffff02330814090000fffe000000007b1938140700f0ffffff0f00007b17303307f80a017b1728491120f0ef0f3307067b17183307167b17103307480b017b170828138219589598019516f830821740aa79ad027b6858027b185897890c9517a020827748826808821a38c8a909821a30d2a9097b696002330a00100a157b6768029517e8207b6748018217687b675001951800317b6858017b676001951858337b6868017b6770018218507b6878017b678001951860337b6888017b6790018217287b670801492610010549262801951840327b68180149262001059517803395180032501070292382659002826b98029517f8308276880233070233083309645a3300720a6401821770c86707821c6033020010532700f01ec82c088287c97809ab5911c9670901828aab7aef7b89330b019516f83081675402816858029519a0207a9750821720be87077a6774027a97549517f0207b6778024926800208951770337b6748018217187b67500195174c337b6758018217107b67600195186c337b6868017b6770018217087b670801492610010349262801951740327b671801492620010395178033951800325010745e2282659002826b98028266880233070233083309645a3300760a640133020010821c60821770c86707532700f01cc82c088287c97809ab590fc9670901828aab7aef7b89019516f830826758028268ab87198217587a674802951844339515a0208157587a8728169589ff951848339515a020ab97098157587a87018328089517f0200a137b6778020a7b57403307780b017b670801951850337b6848018217687b6750017b6858017b676001951870337b6868017b6770019518e0207b6878017b678001951740337b6788018217487b679001492610010549262801951840327b68180149262001059517803395180032501078682182659002826b98029517f8308276880233070233083309645a33007a0a640133020010821770c86707821c60532700f06cfdc82c088287c97809ab595efdc9670901828aab7aee7b89330b01ab7ae62849fd9517443395184833951940337b6948018219487b6950017b6758017b6960017b6868017b6970013307980a017b670801492610010349262801951840327b6818014926200103951780339518003250107cc32082659002826b98029517f8308276880233070233083309645a33007e0a6401821770c86707532700f02182186095870010018278c98709ab590fc9680901827aab8af27b79019515a0208257480a1a9516f8307b6778020a7b57409517e8207b674801951770337b6758019517e0207b6768018217687b6750017b6760017b6770013307c80a017b670801951740327b6718014926100103492620010349262801951780339518003250208000152082659002826b98028266880233070233083309645a330082000a6401821770c86707532700f02c82186095870010018278c98709ab591ac9680901827aab8af27b79330b951a403333080c2823f1951a403333080c2819f100951108f87b10f0077b15e8077b16e0079511c0fb330908ac980a0152070628c31c95790452090628bb1c7c79047b19407c79057b19287c79067b19387c79077b1930958af8957508510a457d583306015908408489ff003306025329c0002d3306035329e000253306045329f0001d3306055329f800153306065329fc000d8898fe009a860801ae6a092897003306017b16486457646864a650208400db2b821a4851077fe4a607c9a70753176076c85a089576a09587607b174851064f7d783305015908378489ff003305025329c0002d3305035329e000253305045329f0001d3305055329f800153305065329fc000d8898fe009a850801ae560628e61b645850208600722b28073305330701e45608c95808e47808c97808330921ae982333083305000001016457951140048210f0078215e8078216e0079511f8073200821948c89505c857077c792051090a3306330a288600958adf957521510a577d573306015907378477ff003306025327c0002d3306035327e000253306045327f0001d3306055327f800153306065327fc000d8877fe009a7608017b1a48ae6a0628431b6457646850208800cb2a821a4828073306330701e46a08c96808e6780ac85606521a241580682064670a0e330833050000012852ff821728977708821840d48707821838978810821930979918d49808d487077b173846115181659517513308017b161864697b1a200a034611526a461153614611546d461155444611564f461157544611586a4611590d46115a4a46115b1946115cd10046115d990046115e5046115f5746116013461161fc0046116265461163f50046116431461165034611668e0046116773330bf100781b68461169d80046116a850046116b6446116c5646116d3246116ec80046116fae0046117050330c3c781c714611724f4611730c4611744d4611755e46117619461177a700461178bf00461179a90046117abb0046117b0f46117ca40046117d960046117e870046117f4746218000e600462181003d781c8200781b830046218400e7009516ff0795669903462185004a462186004946218700dd0046218800c40046218900a60046218a00ec0046218b00a80046218c009a0046218d006a46218e006f46218f0033462190009d0046219100a3004621920033462193007f46219400d20046219500eb0046219600554621970007491148ffef9517980033090001330850208a00671f7b15289557ff330548000133091a7b194054170907288f179777023308000001c887078177c887077b15303207951852330903951a9800330c0001821738330b0a027b677033075000017b17107b67188218407b68209517ff07957709047b67287b68303307c80b017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150208e00a71b826550826b589517ff079577990382764833070233083309645a330090000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677033080150209200a528951752330803951955330a030a037b67788217107b67189517ff07957711047b67283307f80b017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b67309517ff079577e1039518980150209400e91a826550826b5882664833070233083309645a330096000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677833080233050250209800ec27951852330903951a9800330c0001821738330b0a027b6780008217307b67188218407b68209517ff07957719047b67287b68303307280c017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0019517ff079577e1039518980150209a00291a826550826b5882664833070233083309645a33009c000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267800033080550209e002e2795175233080a0f7b6733076000017b67183307580c017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e103951898015020a0008019826550826b5882664833070233083309645a3300a2000a6401821748c86707532700f0db09330740000395770010018278c98709ab59c609c9680901827aab8af17b79330b01ab8ae928b109951852330903951a9800330c0001821738330b0a027b67789517ff07957711047b67283307880c017b1798017b65188218407b68207b68304921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020a600d018826550826b589517ff079577990382764833070233083309645a3300a8000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308013305015020aa00cb259517523308033309330a0a037b6780009517ff07957719047b67483307b80c017b1798014921a001024921b8019517ff079577e1037b17a8017b15b0018217407b67509517ff079577b103951898015020ac001a18826520826b2882661833070233083309645a3300ae000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308023305025020b0001c25951852330903951a9800330c0001821738330b0a027b6733075000017b67183307d80c017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0018217407b67207b66287b67309517ff079577e103951898015020b2006117826550826b5882664833070233083309645a3300b4000a6401821748c86707532700f02402330740000395770010018278c98709ab590f02c9680901827aab8af17b79330b01ab8ae928fa019517583308030a0e7b67789517ff07957711047b67283307080d017b1798017b65188218407b68207b68304921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020b800be16826550826b589517ff079577990382764833070233083309645a3300ba000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308013305015020bc00b9239517583308030a0d7b6780009517ff07957719047b67483307380d017b1798014921a001024921b8019517ff079577e1037b17a8017b15b0018217407b67509517ff079577b103951898015020be000c16826520826b2882661833070233083309645a3300c0000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308023305025020c2000e239517783308030a0d7b6733075000017b67183307580d017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0018217407b67207b66287b67309517ff079577e103951898015020c4006015826550826b5882664833070233083309645a3300c6000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267330805330056012863229517583308030a0f7b67709517ff07957709047b67283307880d017b1798017b65188218407b68207b68304921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020ca00b314826550826b589517ff079577990382764833070233083309645a3300cc000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267703308013305015020ce00ae219517583308030a0d7b67789517ff07957711047b67483307b80d017b1798014921a001024921b8019517ff079577e1037b17a8017b15b0018217407b67509517ff079577b103951898015020d0000214826520826b2882661833070233083309645a3300d2000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308023305025020d400052195187895199800330b03821738330a0a017b67800033075000017b67189517ff07957719047b67283307d80d017b1798014921a001034921b8019517ff079577b1037b17a8018217407b67207b67307b15b0019517ff079577e103951898015020d6004413826550826b5882664833070233083309645a3300d8000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308055020da0049203307e8039518520a067b6733073800017b67183307080e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e103951898015020dc009912826550826b5882664833070233083309645a3300de000a6401821748c86707532700f0f402330740000395770010018278c98709ab59df02c9680901827aab8af17b79330b01ab8ae928ca0295185895199800330b03821738330a0a017b67707b65188218407b68209517ff07957709047b67287b68303307380e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020e200ed11826550826b589517ff079577990382764833070233083309645a3300e4000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267703308015020e600eb1e9517583308030a0d7b67789517ff07957711047b67283307680e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b67309517ff079577e103951898015020e8003511826550826b5882664833070233083309645a3300ea000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308023305025020ec00381e9518588217380a0c7b67800033073000017b17107b67188218407b68209517ff07957719047b67287b68303307980e017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0019517ff079577e103951898015020ee007d10826550826b5882664833070233083309645a3300f0000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308055020f200821d1407ffffffffffff0000951a5833083309330b0a057b678217107b67183307c80e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e103951898015020f400c80f826550826b5882664833070233083309645a3300f6000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382673308063300560128cb1c9517583308030a0e7b67703308015020fa00ba1c7b65188218407b68209517ff07957709047b67287b68303307f80e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020fc00120f826550826b589517ff079577990382764833070233083309645a3300fe000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019517583308030a0d9518ff07958899037b87789517ff07957711047b87283307680e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b87188217407b87207b87309517ff079577e103951898019515980150200001620e9517ff0795779903827650827b588277487b171033070233083309646a330002010a6401821c10821748c8c707532700f023330740000395770010018278c98709ab690fc9c80901827aab8af27b79019517ff0795779903827778330802502004015a1b3309000a9517980133085020060115113306500195185833092064575020080151109566ff9555205206ec9518980133070a069516ff07956699037b6780009517ff07957719047b67583307280f017b6718491620039517ff079577e1037b6728491630028217307b67488217407b67507b67604916389517ff07957799039518ff079588b10350200a01710d826508826b10826633070233083309645a33000c010a6401821748c86707532700f01205330740000395770010018278c98709ab59fd04c9680901827aab8af17b79330b01ab8ae928e8049517583308030a0f7b6780007b65188218407b68209517ff07957719047b67287b68303307880d017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150201001ce0c826550826b589517ff079577990382764833070233083309645a330012010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267800033080150201401cb199517583308030a0d7b673307580f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b66287b67309517ff079577e10395189801502016011e0c826550826b5882664833070233083309645a330018010a6401821748c86707532700f08001330740000395770010018278c98709ab596b01c9680901827aab8af17b79330b01ab8ae928560195185895199800330b03821738330a0a017b6780007b65188218407b68209517ff07957719047b67287b68303307880f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150201c01710b826550826b589517ff079577990382764833070233083309645a33001e010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382678000330801502020016e189517583308030a0d7b673307b80f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b66287b67309517ff079577e1039518980150202201c10a826550826b5882664833070233083309645a330024010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382673308023300560128c41795175833080333098f03330a8f030a097b67707b65188218407b68209517ff07957709047b67287b68303307e80f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e10395189801502028010c0a826550826b589517ff079577990382764833070233083309645a33002a010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677033080150202c010a1795175833088f0333098f030a0a7b67789517ff07957711047b672833071810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b67309517ff079577e1039518980150202e014f09826550826b5882664833070233083309645a330030010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677833080233050250203201521648068f034816084816048f03330801330901951aff0795aa9903330b0133070a057b6780009517ff07957719047b672833074810017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0018217307b67188217407b67207b67309517ff079577e10395189801502034018308826550826b5882664833070233083309645a330036010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382678000330805330056012884159517553308033309330a0a037b676833075000017b17107b67188218407b68209517ff07957701047b67287b683033077810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150203a01c807826550826b589517ff079577990382764833070233083309645a33003c010a6401821748c8670733084000037b1808532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382676833080150203e01c014951755330803951952330a030a037b67709517ff07957709047b67283307a810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217107b67188217407b67207b67309517ff079577e10395189801502040010407826550826b5882664833070233083309645a330042010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267703308023305025020440109149517553308033309330a0a037b67789517ff07957711047b67483307d810017b1798017b15a0014921b8019517ff079577e1037b17a8014921b001018217407b67509517ff079577b10395189801502046015906826520826b2882661833070233083309645a330048010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677833080550204a016113951855330903951a9800330c0001821738330b0a027b6780009517ff07957719047b67283307f810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217107b67188217407b67207b67309517ff079577e1039518980150204c019d05826550826b5882664833070233083309645a33004e010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267800033080650205001a4129517553308033309330a0a037b678217107b671833072811017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e1039518980150205201f304826550826b5882664833070233083309645a330054010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826733080750205601fc1182153001951898008217380a047b67800033080850205801e2117b65188218407b68209517ff07957719047b67287b683033075811017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150205a013a04826550826b589517ff079577990382764833070233083309645a33005c010a6401821748c86707532700f025330740000395770010018278c98709ab5911c9680901827aab8af27b790a28040a019516ff07956699037b6733080950205e0135117b66488217407b675033078811017b1798014921a001024921b8019517ff079577e1037b17a8014921b001019517ff079577b10395189801502060019b03826520826b2882661833070233083309645a330062010a6401821748c86707532700f025330740000395770010018278c98709ab5911c9680901827aab8af27b79330b01821920821a285519217997a6209866203305190003330719000382181850206401a9053a080000031407abaaaaaaaaaaaaaaca7607ae872c821828511809180a08330a450601330702330b11330833090a640195672a330807502066015410320764570a10330ade0001330702330b10330833090a64330820284be400000000009511887b10707b15687b16600a7b17330804502068011a1064177b175033071a7b17583307a811017b1720491128024911409517507b17304911380195170895182050206a018e02821510821b1882160833070233083309645a33006c010a64019568ffef532800f025330740000395770010018278c98709ab5911c9680901827aab8af27b79330b013307000001330882107082156882166095117832009511b87b10407b15387b1630c88909ac895364758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950206e0133821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086f82a70851077282a91051099f0082a8330200103304400003c8240701827ac86a05aca5c300955b0188bc01d8b20bd4cb0b520bb300827bababe57b75330c7b1318c95407957700107b17107b180864957b1450207001c90354250010940082131882181033077b380828b10049130833070128a800330700103302400003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302400003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085464758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a186469502072017bfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206489828a086475510a3582983307958b080182bcc8c70795aaff95bb10520af5829a18510a248288088e88887a1085aa01d4a808897ae0a80852080a330733080128489777010151073e5707776453330800103302400003c8820b0182bcc87c0aacca5e95a501885601d85805d4650552054f82b6abc6e77bbac9a2089588001064352806330801017b177b18084911103308c81101641750207401780652072282171082180882197b57107b58087b5982103082152882162095113832000000008272330900f0952affefac9a2782770833094000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972b7b1a825708c8a707646950207a014f018217c876067b56103307821018821510821608951120320064577b1864a8646950207c0183fc8218825a1028c59511d87b10207b15187b16106486838833098000647aae982c82a81082a7ab781364a764a55020800109fe645a8258100182a708c8870778769588017ba81028ac008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672e7b1a82a708c8570795180c6469502082013fc8560682177b7610013307821020821518821610951128320064a76458646964a55020840173fb645a82551028c2648a3308c8110164a928aa049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200531910488d7a84aa07c8a70b510a0e647c0178c895cc01acbcfbc9a903843cf8c8cb0a580c1d8482ff0014090101010101010101ca920c017bbc95bb08acabfb84390752090a2813647a51090fc8a9090178a895aa01ac9afb3200827701289511a87b10507b15487b16407b18987904330827330aa10601532971027b330827951b3e3a090800037b1910491108f0d80033037b143300ffe0f505016472821710d6720798770b821908c09709c82906976930989932ca39099894119899108499fe07964c9cc86c0c97cc3198cc30c8a9097c967c9901c8ac0c7cc5017ccc78b9ff78b6fe78b50178bc9588fc95bbfcac20ac5417633697793098993296997b14989911969b9cc8b7079777319877309588fec8a7077c7b017c77951c19c88c0c78cb0178c764970155170a149588ff951919c889098377307897281c9777019588fec8a7077c79017c77951a19c88a0a78a90178a701951a19c88a0a9a8b2733088006018217330950208a011382105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208517c7638c94a0a7b19185a1601a0005206ad007b1a1028ac0082752082762864576468821a38821b3050208c0175013308015207be00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b3050208e012101520769821740c95705955501019555ff5105cb00826920330830821748b4900290015107eb28445216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510628825920821748821840b4900292015107ec330801016487821060821558821650951168320082164864676458821918821a38821b30502094018e003308015207d7825a186467821820821928b4a00296013308015207c18217109a777b17383306ff01821738c867075117ff45825920821748821840b4900298019566015107e52839826a18821748821820821928b4a0029a0133080152077eff330882168217107a6730821708786738286aff821610821710d87608285eff821710d876082855ff9511d87b10207b15187b1610839c330200001164a66485647aaa2c21825c2064a764987b1b087b1ab4c0029c01821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b167049116020330a03781a688296204911304911407b17507b185851060a018297285107790149112882957b19088298107b18189578ff9788039888039588017b18955508967838956618330788017b1710017b18208259510918821a588217508258f882aa18b4a0029e01520755018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49002a0015207bb009555108218209588c89566388217289577017b1728520834ff286b829718510773829510330a977804c858087b18207b190882969577ff9777049877049577017b17956608017b1a288269510917821a588217508268f882aa18b4a002a2015207588257825908951830b49002a401520748956610955510821a2895aa01821720ab75c5821908821a829708ac7a0d282d330a829708540726829797a804c88709821a58821750829882990882aa18b4a002a60151070833070128053307018210800082157882167095118800320032009511887b10707b15687b16606493330c3302330b1404fffefefefefefefe330a0a0a0a0a14000a0a0a0a0a0a0a0a8279107b194882797b19308277087b17287b18509588087b1833079106017b170833050a7b13207b14187b1010283ac889077c77ff9577f688770101821a4878a7821728827a18821730b4a002ac016452821320821418821010821c5833050a821b385207670184b7ff0052075b017b1240aec30a28f400acc3f100c9c308821650c8c6065518101daac3dd00330a01c8a6077c77aa57aa0095aa01aba8f428c700956907849af8c96a07d36a0a88aa01887b01d4ba0a7b1c58510a4433079582f001821b588219c89b0b01c8760c82ccc87b098299d30c05c84505e0c50cd309053a0a100003c84505e09509d4c909d2a90952091f957710ae72d32816c8a60b7cbbaa5b5495aa01aba7f59582f0ae72b4aa879900330ac87606c97308821c58c9c80833050a82124001c8a6097c99aa590b95aa01aba8f5282dc87a0a01c8ca0a95ac01ae3a33ff821750c87a0a7ca7ab5727ff285d821c58c8ca0a95ac01ac3ae92815ff643c017b1c584911380164256436aa32528217487c7751071d821728827a18330904821730821808b4a002ae01821240520734c92609821850c82808ab268dfe33072894fe643c82124028b949113864c664c57b1c588217487c775207be28d5330728063307010182107082156882166095117832009511d87b10207b15187b16108275107c59827b827608510933826a187b1808330891060133090464b77b1bb4a002b201821808821b510714330701821020821518821610951128320083879577f68877017857826c2064b7821020821518821610951128320c648a3308f8110164a928a0fb951170ff7b1088007b1580007b167864757c7708648b33080133060151071d7856084615090164578210880082158000821678951190003200649a825c80c7347c580984790452094551083282c82882c720828318330899060133090264a67b1b107b1c08b43002b601821c08821b10646a3308013306015207a764b764c8b4a002b8013308016476289652083782c82882c72082831833089d06013309013306017b1a7b1b107b1c08b43002ba01821c08821b10821a330801520765ff81c7340133060178163782c82082c9287b18187b19209518377b182881c8307cc93882c382c40882c01082c2187a176c7a18687819707b13387b14407b10487b12509517187b17583307f811017b176095183864b7b4a002bc01520721821860821758828a1833089b0601330902b4a002be01647633080128e9fe33080128e3fe51089b0064797c77510791005127ff0090006c7a570a09330a330828735527c0000d330a01330b80284a5527e0000e330a02330b40ff283c5527f0000e330a03330b20ff282e5527f8000e330a04330b10ff28205527fc000e330a05330b08ff2812887afe00330b04ff93ab02ff85aa0701ae8a2b3308c8b70764ab01c8b90c7ccc97880895bbffd4c808520bf28aa903cf9707c88707320032000000009511f8fe7b1000017b15f8007b16f0007b1778180f7b171095160f33050195170f330801951910330a080a037b16603307c4017b176864177b177033071a7b1778492180000249219000024921a000140820000000100000007b18a8004621b000034921b800024921c800027b15d8007b18e0004621e8000333082812017b183049113802951880007b1850491158029518607b1840491148029517189518305020c00104f2821520821b2882161833070233083309645a3300c2010a6401330700f09568ffefac7823330740000395770010018278c98709ab5911c9680901827aab8af27b79330b01821000018215f8008216f0009511080132009511d07b10287b15207b16186486828828826a20828b186475330880060133090164a7b4b002c6017b167817084611097b151033090264179518105020c801ecfc3307017c180852081b8217827828827720828a1833089e0601330901b4a002ca0182102882152082161895113032002124222549112992254992922444a9489624494a9210650a21a2499294242492246992a4902493240989962445a424292245b224494a4a42948a644992949484285308118d4892149122599224294942948a644992a4240951a610221a9124292245b224494a4a42948a644992949484285308118d48921491225992242525214a45b224494a4a42942984882649490a294a9292909442520a492924a5909442520a492924a5909442520a492924a590a42421912445444408899444424242424264929450922449222292a46a12118544a4260ab548444489442222922489882449129124254992444424229124919424499244124944444444444444224484880811212252a54908b1244b3312118990442211112222559a84c4922c8da4121121918844224244a44a93905892a55192244912224913922a49922484903421a9922411409226245521491392aaa43421a90a4935228a50248994aa11124242428a52a4d40891888844888810112249aa3449849464692491a4884844444424424484889024551a49424ab23492884444119188888848444424424484889024551a498294c8529324214989888808111142222222421249952621b1244b8d2449124002481149442244888810112222559a24c4922c8d2449124824128988888888888890c84894884844444424424484881011912a4d124ab23422922422119224492211111111118548a4229154445219894844849088881011912a4d426249961a8988224928800490902049424a22114924491251442422222212111189101121224444a44a93444849961a119124121122121189884884880811212252a59124a4244b234a22229588a48962424424222222222212212242448888489546922025b2d424222211111122444488081111a9d22424966469a48889888848448488082122828848154d426249968a249211119148922449922429898484848484c8a4a98224892449492424242424442605d524490a8b8888922495242591909090901099a48254932452852449922449494a11111111112144448810112212424484104944448410428410220811414408411004411042088210822084105190842492909292885442924424214244448888208948aa6812422cc9d2882448929244244488880849222248922a9a84104bb23422499044a42249229210212222222248922a9a84104bb2342212a40a09112222429244449024553409422c91a52649442a11099124212222444490442455340921966469449220a92222214244442411112449154d428825591a11499044a40a091122222249222248922a9a042196c85293a444244492848888101141129154d124845892a5114982a4884888101111494404495245931062499646441224151222444444924444902455340921966469448924252221922444448488089288a48a2621c4922c8d4812242522214244442411112449154d428825591a91244824152111091122229244440449524593106249964644824885840811112149222248922a9a042196c852934452491291840811112122822422a9a24908b1244b239220291109112222429224228224a9a24908b1244b23920449119224220911222222228224a9a24908b1244b23224100a92a09112222429244449024553409219664694489242541928824448888081111241149154d428825599a149188840811112149121111442449aa6892106249964624414441260549a22222222111914892242222484a154d82104b64a9495224894842848888101141129154d124845892a5119120a91021222224491211419254d12408b144969a24928a2411498810111122224822922a9a84104bb23422122415224444842449222248922a9a84104bb234a244928892242209112222424404494452459310624996462441224a4442848888902489882049aa6812422cc9d2882441242411a98848881011114992880892a48a2621c4922c8d8844922a21492292102122224444904424553409098925591a910449522212224444842449440449524593905892a5114982a44a444244444448222248922a9a84c4922c8d48822422151109112222429224228224a9a249482cc9d28848905425214244444892880892a48a2621b1244b234a90912241928824448888081111241149154d42882559da1125481222444484880892a48a2621c4922c35892484042180245148aa495085a44a7e922c414942224924419254d108219664a9a1242949924a922449a42c85920092699234492a49a208592249a25412490541529224429624494a4d11b22449526aa29454912cc95253a6242949924a922449a42c05250124d32469929452599224294949299322644992a494a82c0905494a4a925e4412624996aa2429a594149494245505a524a9282915944949922492484a12492289a4249244924822999292145296245505a54249922849ad2449922449254b52522aa5952449569224294ad292248900b224a964499d242521242141044b9224491249929294a4249144922449496a24492549499a24544892922429094992949492254992509224494224492541222549524a92248a541224c944929022492a9324992409c992a45492204949485232892421294942a29224499224490a5552299492a44a929a244524912449229192244949225392244492242991244955ca24492449529532499292104992244a52929424654a92849484244992924a4a929290d448a292a42a802080a42449214952924c494249924444924812d1144992244952a64c2949429224292549a22449a6246512495192a4894a4a92242449a2945249a932494a925492845448499254524a920a2522524a92282251254992849484a4241552491292929094c8244992a42449922409492149424249121541a942524814128544215144644a539224a947449424495222250921028810424408894824910449524523126249961a11519294a49042495282242509094912") + # #core_vm_blob = bytes.fromhex("3013001800000101000010ce000000e6000000f80000000a0100002e0100005201000068010000740100008001000092010000696e666f09000000040000000500000007000000726561640200000003000000203a3a2006000000010000007065656b7a65726f080000000b0000000a00000020202020706f6b650010000000000000626c657373406e3d656a656374406e3d657870756e676520206f75747075743d7969656c64406e3d5245464945200000a00001000000000006000000000000007a3d20733d206f5f62797465735f616464726573733d777269746520746f206a616d20406e3d20635f62797465735f6c656e6774683d206f5f62797465735f6c656e6774683d777269746520746f20444f5420406e3d20775f62797465735f6c656e6774683d3a2065787065637420332c20676f74203a2065787065637420cf822b7c657c3d20775f62797465735f616464726573733d20635f62797465735f616464726573733db8000100000000000200000000000000ba000100000000000300000000000000bd000100000000001100000000000000ee0001000000000010000000000000003e0101000000000011000000000000000e0101000000000010000000000000004f010100000000001100000000000000de0001000000000010000000000000006761735f726573756c743d0000000000e0010100000000000b000000000000006d616368696e65206e657720696e6465783d000000000000000201000000000012000000000000006665746368207365676d656e745f696e6465783d2066657463685f726573756c743d000000000000280201000000000014000000000000003c020100000000000e000000000000007a65726f206d3d2c20706167655f69643d207a65726f5f726573756c743d00007002010000000000070000000000000077020100000000000a0000000000000081020100000000000d00000000000000706f6b65206d3d206f3d207a3d20706f6b655f726573756c743d000000000000c0020100000000000700000000000000ba000100000000000300000000000000c7020100000000000300000000000000ca020100000000000300000000000000cd020100000000000d000000000000007a65726f20666f7220726573756c74206d3d0000000000003003010000000000120000000000000077020100000000000a0000000000000081020100000000000d000000000000006265666f7265206368696c645f766d5f7265676973746572733d00000000000078030100000000001a00000000000000696e766f6b652020696e766f6b655f726573756c743d206761733d0000000000a8030100000000000700000000000000af030100000000000f00000000000000be0301000000000005000000000000006f75747075745f62797465733d7c0000f8030100000000000d0000000000000005040100000000000100000000000000050401000000000001000000000000003a206368696c6420564d20696e737472756374696f6e20636f756e7465723d008800010000000000080000000000000038040100000000001f00000000000000be0301000000000005000000000000007065656b206368696c645f766d5f69643d2c207365676d656e745f6275665f706167655f616464726573733d2c206368696c645f706167655f616464726573733d20504147455f53495a453d207065656b5f726573756c743d000000000000008804010000000000110000000000000099040100000000001b00000000000000b4040100000000001500000000000000c9040100000000000b00000000000000d4040100000000000d00000000000000207365676d656e745f6275665b302e2e385d3d2c206368696c645f69643d2c207365675f696e6465783d000000000000380501000000000013000000000000004b050100000000000b0000000000000056050100000000000c000000000000006578706f727420693d2c20676f742000980501000000000009000000000000002e010100000000001000000000000000a1050100000000000600000000000000be030100000000000500000000000000900001000000000008000000000000004143435520000000f8050100000000000500000000000000f805010000000000050000000000000048000100000000000400000000000000726561642066726f6d206a616d20406e3d3a20657870656374204e4f4e452c20676f742020287265636f72646564206174206b657920312930060100000000001100000000000000410601000000000013000000000000005406010000000000140000000000000020287265636f72646564206174206b657920322900000000ce000100000000001000000000000000410601000000000013000000000000009806010000000000140000000000000020287265636f72646564206174206b657920352900000000300601000000000011000000000000001e010100000000001000000000000000e0060100000000001400000000000000666f72676574206a616d20406e3d3a20657870656374204855482c20676f742020287265636f72646564206174206b65792036290000000028070100000000000e00000000000000360701000000000012000000000000004807010000000000140000000000000072656164206a616d406e3d000000000090070100000000000b000000000000001e0101000000000010000000000000005406010000000000140000000000000077726974652064656c65746564206a616d406e3d3a206578706563742070726576206c656e20332c20676f7420000000d0070100000000001400000000000000e40701000000000019000000000000009806010000000000140000000000000090070100000000000b0000000000000041060100000000001300000000000000e0060100000000001400000000000000736f6c696369742068617368286a616d29406e3d3a20657870656374204f4b2c20676f742000000060080100000000001400000000000000740801000000000011000000000000005406010000000000140000000000000071756572792068617368286a616d29406e3d3a20657870656374207a65726f20726573756c742c20676f742000000000b8080100000000001200000000000000ca080100000000001a00000000000000980601000000000014000000000000007175657279206861736828646f7429406e3d0000000000001809010000000000120000000000000041060100000000001300000000000000e0060100000000001400000000000000666f726765742068617368286a616d29406e3d00000000006009010000000000130000000000000074080100000000001100000000000000540601000000000014000000000000003a20657870656374206e6f6e2d7a65726f2c20676f742000b8080100000000001200000000000000a8090100000000001700000000000000980601000000000014000000000000006c6f6f6b7570206861736828646f7429406e3d0000000000f009010000000000130000000000000041060100000000001300000000000000e006010000000000140000000000000061737369676e206a616d406e3d3a2065787065637420434f52452c20676f7420380a0100000000000d00000000000000450a01000000000013000000000000004807010000000000140000000000000070726f766964652068617368286a616d293a206578706563742057484f2c20676f742020287265636f72646564206174206b657920372900880a0100000000002300000000000000ab0a010000000000140000000000000070726f766964652068617368286a616d293a20657870656374204f4b2c20676f742020287265636f72646564206174206b65792038290000e00a0100000000002200000000000000020b01000000000014000000000000006c6f6f6b75702068617368286a616d29406e3d0000000000380b01000000000013000000000000001e010100000000001000000000000000540601000000000014000000000000003a206578706563742057484f2c20676f742000000000000080000100000000000800000000000000800b0100000000001200000000000000e006010000000000140000000000000078000100000000000800000000000000800b010000000000120000000000000048070100000000001400000000000000e00a0100000000002200000000000000ab0a010000000000140000000000000070726f766964652068617368286a616d293a20657870656374204855482c20676f74200000000000180c0100000000002300000000000000020b01000000000014000000000000003a2065787065637420322b325e33322a782c20676f742000b8080100000000001200000000000000600c01000000000017000000000000009806010000000000140000000000000061737369676e406e3d00000000000000a80c010000000000090000000000000074080100000000001100000000000000e00601000000000014000000000000003a3a2065787065637420332c20676f742000000000000000380b0100000000001300000000000000e80c010000000000110000000000000054060100000000001400000000000000b8080100000000001200000000000000a8090100000000001700000000000000540601000000000014000000000000006e657720406e3d3a2065787065637420736572766963655f696e6465782c20676f74200000000000600d0100000000000700000000000000670d0100000000001c00000000000000540601000000000014000000000000007570677261646520406e3d0000000000b80d0100000000000b000000000000007408010000000000110000000000000098060100000000001400000000000000626c65737320406e3d00000000000000f80d010000000000090000000000000074080100000000001100000000000000e006010000000000140000000000000077726974652064656c6574656420444f5420406e3d000000380e01000000000015000000000000004106010000000000130000000000000054060100000000001400000000000000fe0001000000000010000000000000004106010000000000130000000000000054060100000000001400000000000000380e0100000000001500000000000000e4070100000000001900000000000000e0060100000000001400000000000000726561642066726f6d20444f5420406e3d00000000000000e00e01000000000011000000000000004106010000000000130000000000000048070100000000001400000000000000380e010000000000150000000000000041060100000000001300000000000000ab0a0100000000001400000000000000696e666f406e3d00580f010000000000070000000000000074080100000000001100000000000000020b01000000000014000000000000006761733a20676f742020287265636f72646564206174206b6579203929000000900f0100000000000900000000000000990f0100000000001400000000000000636f7265766d20636865636b706f696e740000000000000098000100000000000800000000000000740801000000000011000000000000006f6e5f7472616e73666572206761733a20676f742020287265636f72646564206174206b657920342900000000000000081001000000000015000000000000001d100100000000001400000000000000d40100000000000018000000000000000800000000000000d601000000000000dc01000000000000e4010000000000005b0000000000000006020000000000001800000000000000080000000000000008020000000000000e0200000000000012020000000000002c202c0a0a5d307830303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839395374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20737563636573735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f72206f5f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220737461636b5374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f72206f5f627974657377726974655f726573756c74206b65793d2c20726573756c743d00000000f21201000000000011000000000000000313010000000000090000000000000056555555555555554b598638d6c56d348080808080808080c7610000811602c0f6540d00bb00c600ef001b014601590107021202cb02d60282038d03390444046b0486049804aa04bc04ce04e004f2040405160528053a054c055e057e05f3050b06a80629074507ea0706084308a008bb08520a6d0adf0afa0a710b8c0bf90b140cb40dd30d140edf0eff0e970fb70f6f108f10f8101311b211ca117712921200131c1334145814ab14fd147b159b1512162e16a517c8176e1891181d194019ec190f1a911ab11a461b621bd11bed1b961cb21c701ddd1d561ee11e3f1f5b1f26204220e020fc20a422fb2214235d23db23f42333249f24b824fa2470258925c92525263e267d26fb2614275327be27d7271a2883289c28d12841295a299929fd29162a592ab62acf2a0e2b7e2b972bd62b382c512c932c052d1e2d5d2dc52dde2d1e2e822e9b2ed22e2e2f472f7f2ff82f11304930b330cc300e3176318f31ce3141325a329932fa3213335333aa33c333023421347e34973438355c359e35ae35c03534364c368136fe3617375737b037c937fe376f388838c83821393a397939f039093a483ab03ac93a0b3b873ba03be13b583c713cb03c1c3d353d743de33dfc3d3b3eaf3ec83e083f6b3f843fc23fe33f4e406740ab40f1400a4152419d41fd4116427542a542be424943ec431145eb450f464546704696469d46c8467f47a647ad47c648ea49ae4a034b254b694b964bac4bd64bef4b4b4cfb4c954df84d084e4d4e684e6a4ef14e2f507b50ab50e150575171519c5105521e5270538953c953f1530b542c543a54eb54288c050000282a1c0000285342951178ff7b1080006482808834827784891052091b848820520845827733080164298210800095118800289348827a3308810095177f33035701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830827a3308810095177f33033701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a026427501004424982108000951188003200009511c07b10387b15307b16287b18088289288276827508828720829a183308881001330901b4a001088218087b181078171846111951052d33072a027b17019567017b17087b1620951710951820821950100ad74f9555ff8216085205e47c17180133080152071e821710827828827720828a183308c51001330901b4a0010c64780164878210388215308216289511403200951178ff7b108000648280883484891052091b8488205208467c77330801642982108000951188002849477c77330a810095187f3303570164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e128317c77330a810095187f3303370164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e195b7fe562780002a9aac8100641bc87b0b3309c61001330801330a026427501010f6478210800095118800320000951178ff7b108000648280883484891052092884882052085281778979859801977a2098aa209a77da9a0764298210800095118800288346817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a02642750101432478210800095118800320000951178ff7b108000648280883484891052091b84882052084580773308016429821080009511880028cc45817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a0264275010187b468210800095118800320000951178ff7b108000648280883484891052091b848820520845827733080164298210800095118800281545827a3308810095177f33035701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830827a3308810095177f33033701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a02642750101cc44582108000951188003200009511d07b10287b15207b16186485828828825a20828b186476330888100133090164a7b4b001207b157817084611097b161033050264179518103309025010226c4c9567087b1710641795181064595010245a4c9567107b171064179518106459501026484c9567187b171064179518106459501028364c9567207b17106417951810645950102a244c9567287b17106417951810645950102c124c9567307b17106417951810645950102e004c9567387b171064179518106459501030ee4b9567407b171064179518106459501032dc4b9567487b171064179518106459501034ca4b9567507b171064179518106459501036b84b9567587b171064179518106459501038a64b9567607b17106417951810645950103a944b3307017c180852081a8217827828827720828a183308c51001330901b4a0013c8210288215208216189511303200951108f87b10f0077b15e8077b16e007951128d47b1888007b178000951818319516c02049219000ffffef33075000017b8748013307127b8750013307a800017b17c0004921c800014921e000951860327b18d0004921d80001951710219518c00050103e513f826558826b6082665033070433083309645a3300400a640182189000c8680833020433070000f0ac782433084000039588000010018289c9980aab5a11c9690a01828bab9bf27b8a330c013307000001821b8800ac2b820095b5fc51057b821a80007da70480a933060159073d8477ff003306025327c0002d3306035327e000253306045327f0001d3306055327f800153306065327fc000d8877fe009a760801ae65062897157b19880095a7046468501042894be46508c96809d87908e47909c97909889920d498085108283308330700000128053308013309d82bc891018210f0078215e8078216e0079511f80732007b1780003307400001951818317b8748013307127b8750013307a800017b17c0004921c800014921e000951860327b18d0004921d80001951710219518c0005010441b3e9517c020827558827b6082765033070433083309645a3300460a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79014821b8004921b0004921a8004921a0004921980095179800330924330a033308330b330c0a120195179800330a0833082482198000aca926ff3307440001951818317b8748013307127b8750013307a800017b17c0004921c800014921e000951860327b18d0004921d80001951710219518c0005010485a3d9517c020827558827b6082765033070433083309645a33004a0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b019517c00033090020330850104c2d40951898009519c000330b002082178800330a0a11015117ff68fe7b1788003307300001951518317b5790003307127b5798003307a800019519c0207b9750491958014919709518a8317b986049196801951760329518102150104ea43c82565001825b58018255480133070433083309646a3300500a640182179000c8570753370000f02733074000039577000010018278c98709ab6911c9580901827aab8af27b79330b01821a8800531a03d3fd95a8fd531803cbfd84a7fe511706c3fd95a7f8531703bbfd7c17c2007c18c1007c19c000977710978808d48707d4970795a9f5ac799bfd7c18c5007c1ac4007c1bc30097881097aa08d4a808d4b808c97909ac897cfdc9890653160475fd9512cb00c82703c8380b7cbc037cb5027cba7cb90197cc10975508d45c0cd4c909979908d4a90c9566fcacc646fd7c19c7007c1ac6009799087c16ca007c15c900d4a9097c1ac800976610975508d46505d45a0a95bb043304c020c841067b697b6a087b62107b67187b63207b68287b6b307b6c387b665033081a7b68589517c8207b67607b68689517d0207b67707b68789517d8207b6780007b6888009517e0207b6790007b6898009517e8207b67a0007b68a8009517f0207b67b0007b68b8009517f8207b67c0007b1888007b68c8003307600101951618317b674801492650010849266801951810217b68580149266001089517a83195186032501052f23a82659800826ba0008266900033070333083309645a3300540a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b790a28040a019518c0207b874095170021951618317b679000821788007b6798003307f001017b87509517a8317b876049185801491870491868019517603295181021501056653a82655001826b58018266480133070433083309645a3300580a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515c02082573082583833090a147b574895170821951618317b67900033071a7b67980033071802017b575049155801491570491568019517a8317b5760951760329518102150105ad33982655001826b58018266480133070333083309645a33005c0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b013307340001951618317b6790003307127b6798003307a800019518c0207b8750491858014918709519a8317b896049186801951760329518102150105e4b3982655001826b58018266480133070433083309645a3300600a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019519c02082977b17788297087b17708297107b17688295188298207b186080974882962849218000ff0f9559ff0f98990c3308107b1788000a1701510717330ab41201330702330b3e330833090a6428e6007b165882178000c8670798770c821978c879097b15789557ffff0084770000ff957500000298580c821788000a1701510717330a761201330702330b3e330833090a6428a00082168000821770c8760698690c846700f014080000fefe00000000c9780898880c821788000a1701510716330a3a1201330702330b3c330833090a642861330900000182178800821868821a780a1601510716330afc1101330702330b3e330833090a642839821788008218606459821a580a1601510716330abe1101330702330b3e330833090a642814330a901101330702330b2e330833090a64019518183133074c00017b8790003307127b8798003307a800019519c0207b9750491958014919709518a8317b986049196801951760329518102150106290379517183182755001827b58018276480133070433083309645a3300640a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b0133050810951710213308330908105010665c3a951618314906951718217b670849161049161895171021330a0633087b15786459330b330c0a12017b6768025117ff7e0233071a7b17880033075002017b177033079002017b176833077000017b1760330540000395550000103307e002017b1758282795161831826b95bb017b6b95171021330a063308821978330c0a12017b6768025117ff26027b669000821788007b679800951880337b68a0007b67a8008217707b6748014926500102492668019518a8317b68580149266001029517403195186032501068653695171831827630827b388277287b17800033070433083309646a33006a0a6401821b800082179000c8b70753370000f01a8257c97508ab680fc9b708018259ab79f27b58019518c020808750808854951918317b97107b98183309010a17951918317b974802951728317b974801821788007b975001951830317b9858017b976001951860337b9868017b9770018217687b97900049299800034929b000951760327b97a0004929a80003951740319518a83150106cad3595171831827630827b388277287b17800033070433083309646a33006e0a6401821b800082179000c8b70753370000f01a8257c97508ab680fc9b708018259ab79f27b5801951b183182b91882b71082b808951a10217bba780297990c7bb98802330a00100a16951918317b970801951728317b974801821788007b975001951890337b9858017b9760019518a0337b9868017b9770018218607b9878017b978001951820327b9888017b9790018217587b97900049299800054929b000951760327b97a0004929a80005951740319518a831501070d53495171831827630827b388277287b17800033070433083309646a3300720a6401821b800082179000c8b70753370000f0defd8257c97508ab68d2fdc9b708018259ab79f17b58330a01ab79e928bdfd33073800017b67283307127b67303307a800017b674801492650010149266801951840317b68580149266001019517a831951860325010744c3482659800826ba0008266900033070433083309645a3300760a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b790195161831826918959a018267103308f0ef0fdb9a087b68183309010a177b6720951728317b674801951730317b675801951738317b67680133071a7b6750017b6760017b67700133074803017b679000951760327b67a00049269800034926a800034926b000951740319518a8315010789233826530826b3882662833070433083309645a33007a0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b019516183149165849165049164849164049163849167049167814070000ffff000000007b672814070000fefe000000007b6730826749268000492688004916687b676033075c00017b6708013307127b6710013307a800017b674801492650010149266801951820327b68580149266001019517a8319518603250107ccd3282659800826ba0008266900033070433083309645a33007e0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b0195174031951618317b67080133071e7b67100133079803017b674801492650010149266801951820327b68580149266001019517a8319518603250208000453282659800826ba0008266900033070433083309645a330082000a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b790195131831823228823930823438823040823b48823c50823658823560492390000000018237687b3298008238707b39a0008239787b34a800823a80007b30b000823288007b3bb8007b3cc0007b36c8007b35d000951518317b57d8007b58e0007b59e8007b5af0007b52f80033071a7b17783307c803017b177033064000039566000010019517c0208277489518a8310a197b1880007b570001951708217b5748018217787b575001951818327b5858017b576001951800217b5868017b5770018217707b570801492510010349252801951760327b57180149252001039517a033951820325020840011319517183182759002827b9802827788027b17880033070433083309645a330086000a6401821b880082179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b680195151831825700015107b90085770382188000858864d48707520737ff951740313309689518b0315020880014338257607b1780008257687b17608257707b1788008257787b1768951718318275800049274001492738014927300149272801492720014927180149271001492708019517603233090001330850208a0074339517c02082774895182032821960821a88000a159517c02082774895186032821968645a0a1595182032951a60328217800082198800645b951518310a642892fe33072c00017b5788023307127b5790023307a800017b5748014925500101492568019518a0337b5858014925600101951720329518603250208c00ca2f9517183182751001827b18018276080133070433083309645a33008e000a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b790a28040a019518c0207b874095170021951618317b67880233071a7b6790023307f001017b6748019517a0337b6758014926500101492660010149266801951720329518603250209000332f82651001826b18018266080133070433083309645a330092000a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b019517c020827748951518318258482550027a575402492548027b18705118ffc503330814090000fffe000000007b1968140700f0ffffff0f00007b176033071a7b17800033077000017b17583307e804017b1750491148f0ef0f3307067b17403307167b173833076805017b17303306400003956600001033076400017b17283307127b17203307a800017b171833070e7b17103307a805017b170828148219880095980195151831821770aa7935037b5858027b18880097890c9517c020827748825808821a68c8a909821a60d2a9097b596002330a00100a157b576802951708217b574801821780007b575001951820317b5858017b576001951878337b5868017b5770018218587b5878017b578001951880337b5888017b5790018217507b570801492510010549252801951860327b58180149252001059517a0339518203250209400a02d9517183182759002827b9802827788027b177833070333083309645a330096000a6401821b7882179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b6801951a183181a7540281a858029519c0207a9750821748be87077aa774027a9754951710217ba77802492a800208951790337ba748018217407ba7500195176c337ba758018217387ba7600195188c337ba868017ba770018217307ba70801492a100103492a2801951760327ba71801492a2001039517a0339518203250209800d72c9517183182759002827b9802827788027b177833070433083309645a33009a000a6401821b7882179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b6801951a183182a7580282a8ab8711821788007aa7480295186433280c9589ff95186833ab970d9517c0208177587a87018217287ba788028217207ba790028217187ba74801492a500101492a68019517a0337ba75801492a600101951720329518603250209c00282c9517183182751001827b1801827708017b177833070433083309645a33009e000a6401821b7882179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b680133080810951710210a13951818317b8778020a9518c0207b874095187033951918317b984801821780007b9750017b9858017b976001951890337b9868017b977001951800217b9878017b978001951760337b9788018217107b9790018217087b970801492910010549292801951860327b98180149292001059517a033951820325020a000592b9517183182759002827b9802827788027b177833070433083309645a3300a2000a6401821b7882179000c8b70753370000f0e1fc8267c97608ab58d5fcc9b708018269ab79f17b68330a01ab79e928c0fc9517643395186833951960337b59480133090e7b5950017b5758017b5960017b5868017b59700133070804017b570801492510010349252801951860327b58180149252001039517a033951820325020a400b42a9517183182759002827b98028276880233070333083309645a3300a6000a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515c0208257480a1a951618317b6778020a7b5740951708217b674801951790337b675801951700217b67680133071a7b6750017b6760017b67700133075804017b670801951760327b67180149261001034926200103492628019517a033951820325020a800ff2982659002826b98028266880233070433083309645a3300aa000a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b013307600001951618317b6788023307127b6790023307a800017b6748014926500101492668019518a0337b685801492660010195172032951860325020ac00742982651001826b18018266080133070433083309645a3300ae000a640182179000c8670753370000f03033074000039577000010018278c98709ab591ac9680901827aab8af27b79330b9517603333080c28abea9517603333080c28a1ea00951108f87b10f0077b15e8077b16e0079511a8fb7b18407b17389518ff079588b103491148ffffef33075000017b87183307127b872033070006017b17b0014921b801014921d0019518ff079588c9037b18c0014921c801019517a8009518b0015020b000af288215b000821bb8008216a80033070433083309645a3300b2000a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b01821840531808be02821638520606286b259567045207062862257c67047b17307c67057b17287c67067b17207c67077b17189589f89566085109457d673305015907408477ff003305025327c0002d3305035327e000253305045327f0001d3305055327f800153305065327fc000d8877fe009a750801ae59092847023305017b154064676458646564965020b400c234645982154051072b02e45607c957075317602102c895059576a09557607b174051064f7d783305015908378489ff003305025329c0002d3305035329e000253305045329f0001d3305055329f800153305065329fc000d8898fe009a850801ae560628872464585020b600553428073305330701e45608c95808e47808c97808330920ac98ad01821940c89505c857079585e09577207b17405105537d783306015908378489ff003306025329c0002d3306035329e000253306045329f0001d3306055329f800153306065329fc000d8898fe009a860801ae6506280f2464685020b800dc33ac560c284701330654054201821740c867077c78330a0151080c491140491138288200e46508c96808957501e4a807957bff5518020a3306330728557d573306015907378477ff003306025327c0002d3306035327e000253306045327f0001d3306055327f800153306065327fc000d8877fe009a7608017b1b40ae6b06288823645764685020ba005133821b4001c865057b1538e46b08c96808e678077b17400133074000019518ff079588b1037b87183307127b872033070006017b17b0014921b801014921d0019517ff079577c9037b17c0014921c801019517a8009518b0015020bc0006268215b000821bb8008216a80033070433083309645a3300be000a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b01821840521824338217388078200a0e33083307000001280a3308330700000101951158048210f0078215e8078216e0079511f80732008217289777087b17288217209777107b17208217189777187b171833074400019518ff079588b1037b87183307127b17107b872033070006017b17087b17b0014921b801014921d0019518ff079588c9037b18c0014921c801019517a8009518b0015020c0001f258215b000821bb8008216a80033070433083309645a3300c2000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b790146115782193880977b1758951757330801821a400a03821730821828d487077b1730821720821818d487077b172833073000019518ff079588b1037b87188217107b87208217087b17b0014921b801014921d0019518ff079588c9037b18c0014921c801019517a8009518b0015020c40065248215b000821bb8008216a80033070433083309645a3300c6000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b7901821730821828d487077b17304611626a461163614611646d461165444611664f461167544611686a4611690d46116a4a46116b1946116cd10046116d990046116e5046116f5746117013461171fc0046117265461173f50046117431461175034611768e0046117773330bf100781b78461179d80046117a850046117b6446117c5646117d3246117ec8003306ae0078167f4621800050330c3c781c8100462182004f462183000c462184004d462185005e462186001946218700a70046218800bf0046218900a90046218a00bb0046218b000f46218c00a40046218d00960046218e00870046218f004746219000e600462191003d781c9200781b930046219400e700462195004a462196004946219700dd0046219800c40046219900a60046219a00ec0046219b00a80046219c009a0046219d006a46219e006f46219f00334621a0009d004621a100a3004621a200334621a3007f4621a400d2004621a500eb004621a600554621a700079517a8003309000133085020c800cd2533073400019516ff079566b1037b67183307127b67209517587b672833071a7b673033071006017b17b0014921b801024921d0019518ff079588c9037b18c0014921c801029517ff079577f9039518b0015020ca004a22826550826b5882664833070433083309645a3300cc000a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b018217589577ff5417090728771c9777023308000001c8870781773207951862330903951aa800330c0001821730330b0a029515ff079555b1037b57709577018877019777017b17209517587b571833091a7b59209517ff07957721047b57287b19287b593033076806017b17b0014921b801034921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020d0006a21825650825b5882554882172033083309646a3300d2000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267703308015020d4009d2e951762330803951965330a030a039518587b68189518ff07958829047b68288218287b68207b68303308b006017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67789577018877019777017b17289517ff079577f9039518b0015020d600a620826550826b5882664882172833083309645a3300d8000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b1038257783308023306025020da00d62d951862330903951aa800330c0001821730330b0a027b5780009577fd8877019777017b17209517587b571833091a7b59209517ff07957731047b57287b19287b59303307f806017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b0015020dc00d51f825650825b5882554882172033083309646a3300de000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b103826780003308055020e000072d95176233080a0f9518587b68188218287b68207b683033086007017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b679577098877019777017b17287b66289517ff079577f9039518b0015020e200201f826550826b5882664882172833083309645a3300e4000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308063300b00128502c951862330903951aa800330c0001821730330b0a029515ff079555b1037b57789577fd8877019777017b17209517587b571833091a7b59209517ff07957729047b57287b19287b59303307a007017b17b0014921b801034921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020e8004a1e825650825b5882554882172033083309646a3300ea000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267783308015020ec007d2b9517623308033309330a0a039518587b68189518ff07958831047b68288218287b68207b683033080008017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780009577fd8877019777017b17289517ff079577f9039518b0015020ee00871d826550826b5882664882172833083309645a3300f0000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b103826780003308023305025020f200b62a951862330903951aa800330c0001821730330b0a029518587b681833081a7b68207b683033083008017b18b0014921b801034921d0019518ff079588c9037b18c0017b15c8017b679577018877019777017b17287b66289517ff079577f9039518b0015020f400c21c826550826b5882664882172833083309645a3300f6000a6401821748c8670753370000f0580233074000039577000010018278c98709ab594102c9680901827aab8af17b79330b01ab8ae9282c023306039517683308030a0e9515ff079555b1037b57788877019777017b17209517587b571833081a7b58209517ff07957729047b57287b18287b583033078808017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020fa00041c825650825b5882554882172033083309646a3300fc000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267783308015020fe0037299517683308030a0d9518587b68189518ff07958831047b68288218287b68207b68303308e808017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780008877019777017b17289517ff079577f9039518b00150200001481b826550826b5882664882172833083309645a330002010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b10382678000330802330502502004017728951788003308030a0d9518587b681833081a7b68207b683033083009017b18b0014921b801034921d0019518ff079588c9037b18c0017b15c8017b679577018877019777017b17287b66289517ff079577f9039518b001502006018f1a826550826b5882664882172833083309645a330008010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308053300b00128bf273306039517683308030a0f9515ff079555b1037b57688877019777017b17209517587b571833081a7b58209517ff07957719047b57287b18287b583033077809017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150200c01c719825650825b5882554882172033083309646a33000e010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b10382676833080150201001fa269517683308030a0d9518587b68189518ff07958821047b68288218287b68207b68303308c009017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67708e779777017b17289517ff079577f9039518b001502012010d19826550826b5882664882172833083309645a330014010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b103825770330802330602502016013d26951888009519a800330b03821730330a0a017b57789577018877019777017b17209517587b571833091a7b59209517ff07957729047b57287b19287b59303307080a017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b001502018014018825650825b5882554882172033083309646a33001a010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b10382677833080550201c0173253307e8039518620a069518587b68189518ff07958831047b68288218287b68207b68303308580a017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780009577068877019777017b17289517ff079577f9039518b00150201e018017826550826b5882664882172833083309645a330020010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b1038257800033080650202201b22433079a029518683309030a1b7b17289577048877019777017b17189517ff07957721047b574833071a7b17207b57503307c00a017b17b0014921b801024921d0019517ff079577f9037b17c0014921c801019517ff079577c9039518b00150202401c316825620825b2882551882171833083309646a330026010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b790133080782172850202801fe239518683309038217300a1b9516ff079566b1038218207b68503308180b017b18b0014921b801024921d0019518ff079588f9037b18c0014921c801017b678877019777017b17207b66489517ff079577c9039518b00150202a011716826520826b2882661882172033083309645a33002c010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79013308088217283300b001284e233306039518689519a800330b03821730330a0a017b17a8019577fd8877019777017b17209517589515ff079555b1037b571833081a7b58209517a8017b57287b18287b58303307500b017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b001502030014d15825650825b5882554882172033083309646a330032010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79018217a8013308015020340187229517683308030a0d9516ff079566b1039518587b68189518ff07958819047b68288218287b68207b68303308c009017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67688e779777017b17289517ff079577f9039518b001502036019214826550826b5882664882172833083309645a330038010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b10382576833080233060250203a01c2219518688217300a0c7b57709577048877019777017b17209517587b571833081a7b58209517ff07957721047b57287b18287b58303307980b017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b00150203c01cf13825650825b5882554882172033083309646a33003e010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267703308055020400102211407ffffffffffff0000951a6833083309330b0a059518587b68189518ff07958829047b68288218287b68207b68303308c80b017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67789577048877019777017b17289517ff079577f9039518b001502042010413826550826b5882664882172833083309645a330044010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b1038267783308065020460137209518683309038217300a1b7b6780008877019777017b17209517ff07957731047b674833071a7b17287b67503307f80b017b17b0014921b801024921d0019517ff079577f9037b17c0014921c801019517ff079577c9039518b001502048014b12826520826b2882661882172033083309645a33004a010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b1038267800033080750204c017d1f9518683309038217300a1b8218287b68503308400c017b18b0014921b801024921d0019518ff079588f9037b18c0014921c801017b679577098877019777017b17287b66489517ff079577c9039518b00150204e019b11826520826b2882661882172833083309645a330050010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308083300b00128cb1e3306039517683308030a0e9515ff079555b1037b577033080150205401af1e8257708877019777017b17209517587b571833081a7b58209517ff07957721047b57287b18287b583033078808017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150205601c710825650825b5882554882172033083309646a330058010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019517683308030a0d9519ff079599b1039518587b98189518ff07958829047b98288218287b98207b98309519ff079599b1033308780c017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b97788e779777017b17289517ff079577f9039518b0019515b00150205a010d109517ff079577b103827650827b588277487b172082172833083309646a33005c010a6401821c20821748c8c70753370000f02533074000039577000010018278c98709ab690fc9c80901827aab8af27b79019517ff079577b10382777833080250205e01321d3309000a9517b001330850206001c31233065001951868330920645750206201ff119566ff9555205206ec9518b00133070a069515ff079555b1037b5780008877019777017b17289517587b574833071a7b57509518ff07958831047b58587b57603307b80c017b5718491520034915389517ff079577f9037b5728491530029517ff079577b1039518ff079588c90350206401110f825608825b10825582172833083309646a330066010a6401821748c8570753370000f0790533074000039577000010018278c98709ab696205c9580901827aab8af17b79330b01ab8ae9284d053306039518689519a800330b03821730330a0a019515ff079555b1037b5780009577fd8877019777017b17209517587b571833081a7b58209517ff07957731047b57287b18287b58303307000d017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150206a01470e825650825b5882554882172033083309646a33006c010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267800033080150206e01791b9517683308030a0d9518587b68188218287b68207b68303308c009017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b678e779777017b17287b66289517ff079577f9039518b00150207001950d826550826b5882664882172833083309645a330072010a6401821748c8670753370000f0960133074000039577000010018278c98709ab597f01c9680901827aab8af17b79330b01ab8ae9286a013306039517683308030a0f9515ff079555b1037b5780008877019777017b17209517587b571833081a7b58209517ff07957731047b57287b18287b583033077809017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150207601d60c825650825b5882554882172033083309646a330078010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267800033080150207a01081a9517683308030a0d9518587b68188218287b68207b68303308300d017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b678e779777017b17287b66289517ff079577f9039518b00150207c01240c826550826b5882664882172833083309645a33007e010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308023300b00128541933060395176833080333098f03330a8f030a098e789515ff079555b1037b57709788017b18209517587b571833081a7b58209517ff07957721047b57287b18287b58303307880d017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150208201550b825650825b5882554882172033083309646a330084010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b10382677033080150208601881895176833088f0333098f030a0a9518587b68189518ff07958829047b68288218287b68207b68303308c80d017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67788877019777017b17289517ff079577f9039518b00150208801950a826550826b5882664882172833083309645a33008a010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b10382577833080233060250208c01c51748058f034815084815048f03330801330901951aff0795aab103330b0133070a057b5780008877019777017b17289517587b571833071a7b57209518ff07958831047b58287b57303307080e017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b00150208e01be09825650825b5882554882172833083309646a330090010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019517ff079577b103827780003308053300b00128ec163306039517653308033309330a0a039515ff079555b1037b57689577018877019777017b17209517587b571833081a7b58209517ff07957719047b57287b18287b58303307500e017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150209401ed08825650825b5882554882172033083309646a330096010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b103826768330801502098012016951765330803951962330a030a039518587b68189518ff07958821047b68288218287b68207b68303308800e017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67709577018877019777017b17289517ff079577f9039518b00150209a012908826550826b5882664882172833083309645a33009c010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b10382577033080250209e015c153306039517653308033309330a0a037b57789577fd8877019777017b17209517587b571833081a7b58209517ff07957729047b57287b18287b58303307b00e017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020a0016207825650825b5882554882172033083309646a3300a2010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267783308055020a4019514951865330903951aa800330c0001821730330b0a029518587b68189518ff07958831047b68288218287b68207b68303308f80e017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780009577018877019777017b17289517ff079577f9039518b0015020a6019606826550826b5882664882172833083309645a3300a8010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b103825780003308065020aa01c8133306039517653308033309330a0a037b579577018877019777017b17289517587b571833071a7b57207b55287b57303307280f017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020ac01da05825650825b5882554882172833083309646a3300ae010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019517ff079577b10382773308075020b0010e139518a8008217300a0464759517ff079577b1037b757833080864575020b201ed128857019777017b17289517589519ff079599b1037b971833081a7b98209517ff07957729047b97287b18307b98309515ff079555b1033307600f017b17b0014921b801034921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020b401f704825650825b5882554882172833083309646a3300b6010a6401821748c8570753370000f02733074000039577000010018278c98709ab6911c9580901827aab8af27b790a28040a019516ff079566b1037b6780003308095020b80125129517ff07957731047b67488217307b67503307b00f017b17b0014921b801024921d0019517ff079577f9037b17c0014921c801019517ff079577c9039518b0015020ba015404826520826b2882661833070433083309645a3300bc010a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b018219405519212101330519000333071900038218385020be016d068218583a090000031407abaaaaaaaaaaaaaaca7807ae9738330733511809270a08330ad00f01330703330b11330833090a6482175895772a3308073300c0012839113308075020c0013311320764570a109515ff079555b1037b578877019777017b17409517587b571833071a7b57207b55287b57303307e80f017b17b0014921b801024921d0019518ff079588c9037b18c0014921c801029517ff079577f9039518b0015020c2014803825650825b5882554882174033083309646a3300c4010a6401821748c8570753370000f03133074000039577000010018278c98709ab691bc9580901827aab8af27b79330b3307190003330820285edd33071900033308202853dd00000000009511887b10707b15687b16600a7b173308045020c6015b1064177b175033071a7b175833073810017b1720491128024911409517507b1730491138019517089518205020c801a002821510821b1882160833070433083309645a3300ca010a64019568ffffef53380000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b013307000001330882107082156882166095117832009511b87b10407b15387b1630c88909ac895364758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a1864695020cc0133821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206495647251087a82a70851077d82a9105109ab0082a833064000033303000010c8360601826ac85a07aca7d000957b0188bc01d8b30bd4cb0b520bc000826bababe57b67330c7b1218330a400003330b0000107b1ac8ba0ac97a077b17107b180864965020ce01d3035436000010980082121882181033077b280828b50049120833070128ac0033094000033307000010c8790901829ac85a08aca85f958b0188bc01d8b70bd4cb0b520b50829bababe77b98330c01ababdf283133094000033307000010c8790901829ac85a08aca82b958b0188bc01d8b70bd4cb0b520b1c829bababe77b98330c013307400013c9870833077b280828393307017b27082831646c82179577000010821218821608018278c98709ab6911c9c80901827aab8af27b79330b0182181033077b2808017b25107b2782103082152882162095113832009511b87b10407b15387b163095880151085464758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a1864695020d0016cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206489828a086475510a3582983307958b080182bcc8c70795aaff95bb10520af5829a18510a248288088e88887a1085aa01d4a808897ae0a80852080a3307330801284a977701015107405707796452330b4000033308000010c88b0b0182bcc87c0aacca5f95a501885601d85805d4650552055082b6abc6e77bba3308400013c9a80864252806330801017b177b1808491110330858100164175020d2019e0652072282171082180882197b57107b58087b598210308215288216209511383200000000827233090000f0952affffefac9a288277083309400003959900001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972b7b1a825708c8a70764695020d8014f018217c876067b56103307821018821510821608951120320064577b1864a864695020da016ffc8218825a1028c59511d87b10207b15187b16106486838833098000647aae982c82a81082a7ab781364a764a55020de0104fe645a8258100182a708c8870778769588017ba81028ac008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672e7b1a82a708c8570795180c64695020e0013fc8560682177b7610013307821020821518821610951128320064a76458646964a55020e2015ffb645a82551028c2648a330858100164a928cd049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200531910488d7a84aa07c8a70b510a0e647c0178c895cc01acbcfbc9a903843cf8c8cb0a580c1d8482ff0014090101010101010101ca920c017bbc95bb08acabfb84390752090a2813647a51090fc8a9090178a895aa01ac9afb3200827701289511a07b10587b15507b16487b19087b18987a04330927532a71028100330927951b463a080800037b1818491110f0d80033037b143305c810013300ffe0f505016474821718d6740798770b821810c08702c8420a97a230982832ca3808988c119888108488fe0796cc9cc8ca0a97aa3198aa30c858087c8c7c8801c85a0a7ca6017caa78b8ff78bcfe78b60178ba9599fc95bbfcac40ac5417633b97783098883296887b14988811968a9cc8a7079777319877309599fe330ac81001c8a7077c7a017c77951b21c89b0b78ba0178b764870155170a149599ff951821c89808837730788728219777019599fe3308c81001c887077c78017c77951a21c89a0a78a80178a701951b21c89b0b9a9c2733098810018217088218330a5020e8011382105882155082164895116032009511987b10607b15587b16507b1b1851084f807634846801330b2b3305000011db8b057b1528c8c8028468045108427b19303308510a1a64a5017d9b89bbc085bb01c8b8089555ff9599015205efc882027b1a3882787b1c20520823284181763495c2014911282d8468045208c44911307b1a3882787b1c20510824827508ae521e8466085206517c7938c9250a5a1901a4005209b1007b1a1028b00082752082762864576468821928821a30821b385020ea0176013308015207bf00826c186457821818821920821060821558821650951168320c7b12408178307b18087c79387b19827920827628481730307b1710461738017b194864976468821928821a30821b385020ec012101520769821740c97505955501019555ff5105cb00826920330830821748b49002ee015107eb28445219021298a90195a8019888017b1810280864a9491110018278207b18488276288177307b1740959501019555ff510528826920821748821840b49002f0015107ec330801016487821060821558821650951168320082154864576468821928821a30821b385020f2018e003308015207d7826a186457821818821920b4a002f4013308015207c18217109a777b17383305ff01821738c857075117ff45826920821748821840b49002f6019555015107e52839826a18821748821818821920b4a002f80133080152077eff33088217108219087a79308219787938286aff821510821710d87508285eff821710d875082855ff9511d87b10207b15187b1610839c330200001164a66485647aaa2c21825c2064a764987b1b087b1ab4c002fa01821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b167049116020330a03781a688296204911304911407b17507b185851060a018297285107790149112882957b19088298107b18189578ff9788039888039588017b189555089678389566183307e6017b1710017b18208259510918821a588217508258f882aa18b4a002fc01520755018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49002fe015207bb009555108218209588c89566388217289577017b1728520834ff286b829718510773829510330a977804c858087b18207b190882969577ff9777049877049577017b17956608017b1a288269510917821a588217508268f882aa18b4a00200025207588257825908951830b490020202520748956610955510821a2895aa01821720ab75c5821908821a829708ac7a0d282d330a829708540726829797a804c88709821a58821750829882990882aa18b4a002040251070833070128053307018210800082157882167095118800320032009511807b10787b15707b166864923300330b33051403fffefefefefefefe330a0a0a0a0a14040a0a0a0a0a0a0a0a8279107b194882797b19388277087b173033076800017b17083a071000037b17607b18589588087b18330c0a7b12207b13187b1410283b6406c889077c77ff9577f688770101821a4878a7821730827a18821738b4a0020a02645b8212208213188214106460330c0a821540520764018457ff00520758017b1b50ae020a28ef00ac02ec00c90208821658c806065518101daa02d800330a01c8a6077c77aac7a50095aa01aba8f428c200956907849af8c96a07d36a0a88aa01887b01d4ba0a510a453307958af0821bc80b0b2808821bc80b0b01c8760c82ccc87b098299d34c05c83505e0c50cd34905c83505e09509d4c909821c60d2c90952091f957710ae7ad52816c8a60b7cbbaacb5195aa01aba7f5958af0ae7ab9aa879b00330ac87606c97208c90808330c0a821b5001c8a6097c99aac90b95aa01aba8f5282dc87a0a01c80a0a95a001ae2a38ff821758c87a0a7ca7abc72cff2862821b50c80a0a95a001ac2ae9281aff6420014911400164b56426aa2b578217487c77510723821730827a183309048217388218087b1028b4a0020c02821b50821028520733c9b609821858c8b808abb68efe640633072895fe6420821b5028b4491140640564068217487c775207b928d633072806330701018210788215708216689511800032009511d87b10207b15187b16108275107c59827b827608510933826a187b1808330868000133090464b77b1bb4a0021002821808821b510714330701821020821518821610951128320083879577f68877017857826c2064b7821020821518821610951128320c648a330890100164a92899fb951170ff7b1088007b1580007b167864757c7708648b33080133060151071d7856084615090164578210880082158000821678951190003200649a825c80c7347c580984790452094551083282c82882c7208283183308c0100133090264a67b1b107b1c08b430021402821c08821b10646a3308013306015207a764b764c8b4a00216023308016476289652083782c82882c7208283183308c410013309013306017b1a7b1b107b1c08b430021802821c08821b10821a330801520765ff81c7340133060178163782c82082c9287b18187b19209518377b182881c8307cc93882c382c40882c01082c2187a176c7a18687819707b13387b14407b10487b12509517187b175833079010017b176095183864b7b4a0021a02520721821860821758828a183308c21001330902b4a0021c02647633080128e9fe33080128e3fe51089b0064797c77510791005127ff0090006c7a570a09330a330828735527c0000d330a01330b80284a5527e0000e330a02330b40ff283c5527f0000e330a03330b20ff282e5527f8000e330a04330b10ff28205527fc000e330a05330b08ff2812887afe00330b04ff93ab02ff85aa0701ae8a2b3308c8b70764ab01c8b90c7ccc97880895bbffd4c808520bf28aa903cf9707c88707320032000000009511f8fe7b1000017b15f8007b16f0007b1778180f7b171095160f33050195170f330801951910330a080a037b1660330722027b176864177b177033071a7b1778492180000249219000024921a000140820000000100000007b18a8004621b000034921b800024921c800027b15d8007b18e0004621e8000333081013017b183049113802951880007b1850491158029518607b18404911480295171895183050201e02d5f1821520821b2882161833070233083309645a330020020a640133070000f09568ffffefac782433074000039577000010018278c98709ab5911c9680901827aab8af27b79330b01821000018215f8008216f0009511080132009511d07b10287b15207b16186486828828826a20828b186475330888100133090164a7b4b00224027b167817084611097b151033092a02641795181050202602e8fc3307017c180852081b8217827828827720828a183308c51001330901b4a00228028210288215208216189511303200951178ff7b1080006482808834827784891052091b8488205208467c77330801642982108000951188002866f47c77330a810095187f3303570164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e128317c77330a810095187f3303370164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e195b7fe562780002b9aac8100641bc87b0b3309c61001330801330a02642750202c0213f582108000951188003200002124a29424a58814c99224292915c992242929095142528868922425098924493449524892499284444b92224a92942252244b922425a9489624494a921025248588469424a924a58814c99224292915c99224292909514252886844499252448a64499294948a6449929494842821294434a22449292245b224494a4a45b224494a4a42949014229a242529a428494a42520a492924a5909442520a492924a5909442520a492924a590944292928444921411111111811089102122424448922a8d24248425596a8848222591909090901099440a499224851a89882842442244888810112249aa341284b0244b23222292aa914484884488101121224492546924086149961a518888a821424422442291880811912a8d04212cc9522324242444449224222249120991242549924444221249924849922449249144444444444444448488101121224444aa341284b0244b3b12111121914844848848954682109664692495884884442212112222551a09425892a586884488442211112222551a09425892a5519224491244124d48aa24922421844413922a91240248a209495588a4094955a43421a90a4935422442241289881011912a8d04212cc952238a10459248a91a21111212124248518a941a2122222211222244844812a9d2880425591a49242922222222222211222244844812a9d2880425591a4922125144444444444422222211222244844812a9d288044a64a9494812224444880811912a8d04212cc9d248129294888888444488881022222449954682109664a9912449024800292209910811222244848848954682109664a9119108112222440411912a1a09425892a59124491248241211111111111191848430124544242222221221224244101111a9a211094ab2342212494422482489242222222222a220128922918a88284a88448810112122888848158d04212cc9d28e44442244440811114444aa6824086149961a892222a100124012212141928484109284242145221191489224a288888888884844442442448488202222a9a2890425591a119124121122121189884884880811414444524513094ab234a2444489449a482442448488202222a9a2890425591a51c4484444444444444424122122424410119154d1440225b2d42422221111112244448808222252452341084bb23452c4444444242242448410114144a48a4682109664a92122112244448808222255341284b0244b4512c98888482282902444888808114144a48a2641084bb2d4842449922449929444424242424264d254052592902429898484848484c8a4a09a2489244952120909090909914941522425499224519544424242424264920a3249922122498810111122828848154d82109664a989a442851111519224494244928444888808114144a48a2641084bb23429494a922409114912212222440411912a9a04212cc9d22489888888880821224284881091102222444222841042100441088220042122082108822008420841104210841051102292244988101111222248922a9a04212cc9529348422a89484524499224224988101111222248922a9a04212cc9d28824489292882409112222429224228224a9a24910c2922c8d48122411a948922489481222444444440449524593208425591a110952499210212222942489882049aa681284b0244b234a2489484524499224224988101111222248922a9a04212cc9d2882448aa2422494284888810491211419254d124086149964644122411a92449881011112549222248922a9a044258224b4d921491244912912444444484880892a48a2641084bb23422099292882409112222422489882049aa681284b0244b2322092225494284888828491211419254d1240861499646944892229224492292848888881011419254d1240861499646244152129124214244444849440449524593208425591a912488482a49922411494284888888882049aa681284b0244b2392205212912421424444882489882049aa681284b0244b2322412425492292244488880811112449154d8210966469122429220911222242491211419254d12408614996269124928a24494492481222222242440449524593208425591a09922292882409112222424a222248922a9a04212cc9d2882441529224492292840811111111419254d1240861499646244100a94a229224448888084992880892a48a2641084bb23422099214492292244488880811112449154d8210966469442448521222444484922411112449154d82109664694489242922099224492292848888881011419254d124086149962645241149121122444484944444041149922a9a24086149964624414441260549a222224992442421918844444490942a9a044258224b4d92482a229224492292848888881011419254d12408614996464482a42449881011112a4944044952459340084b64a949922222499244240911111121228224a9a24910c2922c8d8804494992102122225492880892a48a2641084bb234a24492445444922489481222222242440449524593208425591a91048928894892102122222449440449524593208425591a91248884242215499224220911222222228224a9a24910c2922c8d884492541149922489481222222242440449524593208425591a9104495212912421424444489244449024553409425892a5114990a44a922449449210111111222248922a9a04212cc9d2882448225249449284081111219224228224a9a24910c2922c8d880449aa9224499210111111222248922a9a04212cc9d28812442a222948928824114922428488881011419254d1240861499676442488481222444484880892a48a2641084bb2d4841012240490240a49952492a08a284992242142444488882049aa681284b0244b8524243f4996a024219124922049aa6808425892a58692a424492a49922491b2144a0248a649d224a9248942c8124912a51242495210484a9284902549925253085992242935a49454215992a5a64c495292249524499248590a4a0248a649d22429a5b2244952929252268590254992524865492848525292f44248425892a52a494a292505252549554129492a4a4a0565529224892492924492482229892491249248a6a424859425495541a95092244a522b4992244952c99294944a692549929524498a92b4244922802c492a595227494a82242488102c4992244924494a5292924412499284a4243592a4929094a449422a24494992240949929496244952521249529224498824a924412225495292944422952448928924214592542649324912922549a92441929290a46412494252928444494a9224499214aaa452282549952435498a4822499244222549929244a6244988244952224992aa9449924892a42a659224252192244994a4242949ca9424092909499224259594242521a99144254955004100494942429292a492644a124a52121149224944532449922429a532a524499224292549a224c994a44c22294a92342a294992842449a2524aa55499244a925492845448499254524a920a2522524a92282251254992849484a4241552491292929094c8244992a42449922409492149424249121541a942524814128544215144644a539224a94744942449522225092102881042440889482491044952454348084bb2d4888892a42485144a1225485292909024459492a4149122599224294945b224495292842821298828") + # + # #core_vm_child_blob = bytes.fromhex("2a020008000001010000106d61696e010000004348494c4c200000080001000000000006000000000000004348494c44204e4f524d206e3d206669625f6e5f323d20726573756c743d202861646472323d202861646472313d29206669625f6e5f313d2920726573756c743d0000000000000020000100000000000d000000000000002d0001000000000009000000000000003e0001000000000008000000000000004e000100000000000a0000000000000046000100000000000800000000000000580001000000000009000000000000004348494c442042415345206e3d000000c8000100000000000d00000000000000360001000000000008000000000000004348494c44205752495445206f75745f616464726573733df80001000000000018000000000000003600010000000000080000000000000026000000000000001800000000000000080000000000000028000000000000002e000000000000003600000000000000307830303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839394b598638d6c56d34431200002b028feb0300bc00c70073017e012a028802a00218033303060421049a04b5044c05ee051207e40708083e0868088d089408be0874099a09a109560a790b3c0c900cb10cf40c200d350d5e0d760dd00d850e1e0f7d0f8c0fd00f283502951178ff7b108000648280883484891052092884882052085281778979859801977a2098aa209a77da9a076429821080009511880028220a817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309600101330801330a026427501004d00a8210800095118800320000951178ff7b108000648280883484891052091b848820520845807733080164298210800095118800286b09817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309600101330801330a026427501008190a8210800095118800320000951178ff7b108000648280883484891052091b84882052084582773308016429821080009511880028b408827a3308810095177f33035701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830827a3308810095177f33033701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309600101330801330a02642750100c62098210800095118800320000951100ff7b10f8007b15f0007b16e800491108ffffef7b177b171033070400017b17d0003307027b17d80033071000017b177049117801492190009518d0007b188000492188000195174095187050100ebd04821648821b5082154033070433083309646a3300100a6401821708c8570753370000f02733071000039577000010018278c98709ab6911c9580901827aab8af27b79330b018218551802990048111c019518107b184033080a7b184895181c7b18503308067b18583308d800017b187049117802492190009518407b18800049218800029517d0009518705010122d048215d800821be0008216d00033070233083309645a3300140a6401821708c8670753370000f0150133071000039577000010018278c98709ab59fe00c9680901827aab8af17b79330b01ab8ae928e90097870c140800e0fefe00000000c878087b182081887a182c140900f0fefe00000000c897077b173081777a173cbe87077a171c9517107b177033070a7b177895182c7b1880003308067b1888009519207b1990007b17980095193c7b19a0007b18a8009519307b19b0007b17b80095171c7b17c0007b18c80033076800017b1740491148064911609518707b1850491158069517d0009518405010163f038215d800821be0008216d00033070233083309645a3300180a6401821708c8670753370000f02733071000039577000010018278c98709ab5911c9680901827aab8af27b79330b0181171097770c83770000fffe7a17309517307b17403307067b174895181c7b18507b175833071001017b177049117802492190009518407b18800049218800029517d00095187050101aab028215d800821be0008216d00033070233083309645a33001c0a6401821708c8670753370000f02733071000039577000010018278c98709ab5911c9680901827aab8af27b79330b0180173081181c7a78801730330800108210f8008215f0008216e8009511000132009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101e32821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206495647251087982a70851077c82a9105109aa0082a833061000033303000010c8360601826ac85a07aca7cf00957b0188bc01d8b30bd4cb0b520bbf00826bababe57b67330c7b1218330a100003330b0000107b1ac8ba0ac97a077b17107b18086496501020bb035436000010980082121882181033077b280828b50049120833070128ac0033091000033307000010c8790901829ac85a08aca85f958b0188bc01d8b70bd4cb0b520b50829bababe77b98330c01ababdf283133091000033307000010c8790901829ac85a08aca82b958b0188bc01d8b70bd4cb0b520b1c829bababe77b98330c013307100013c9870833077b280828393307017b27082831646c82179577000010821218821608018278c98709ab6911c9c80901827aab8af27b79330b0182181033077b2808017b25107b2782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a1864695010226dfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b1620828a086475510a3582893307959b080182bcc8c70795aaff95bb10520af5828a18510a248299088e99887a1085aa01d4a909897ae0a90952090a3307330901284a977701015107405707736452330b1000033309000010c89b0b0182bcc87c0aacca5995a501885601d85905d4650552054a82b6abc6e77bba3309100013c9a90964252806330901017b177b19084911106417501024290652072282171082180882197b57107b58087b598210308215288216209511383200000000827233090000f0952affffefac9a288277083309100003959900001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950102a41018217c876067b56103307821018821510821608951120320064577b1864a8646950102c7bfc8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a55010300ffe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950103234c8560682177b7610013307821020821518821610951128320064a76458646964a55010346efb645a82551028c42867049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a07b10587b15507b16487b19087b18987a04330927532a71028100330927951b463a080000037b1818491110f0d80033037b1433056201013300ffe0f505016474821718d6740798770b821810c08702c8420a97a230982832ca3808988c119888108488fe0796cc9cc8ca0a97aa3198aa30c858087c8c7c8801c85a0a7ca6017caa78b8ff78bcfe78b60178ba9599fc95bbfcac40ac5417633b97783098883296887b14988811968a9cc8a7079777319877309599fe330a620101c8a7077c7a017c77951b21c89b0b78ba0178b764870155170a149599ff951821c89808837730788728219777019599fe3308620101c887077c78017c77951a21c89a0a78a80178a701951b21c89b0b9a9c2733096001018217088218330a50103a1282105882155082164895116032009511987b10607b15587b16507b1b1851084f807634846801330b2b3305000011db8b057b1528c8c8028468045108427b19303308510a1a64a5017d9b89bbc085bb01c8b8089555ff9599015205efc882027b1a3882787b1c20520823284181763495c2014911282d8468045208c44911307b1a3882787b1c20510824827508ae521e8466085206507c7938c9250a5a1901a1005209ae007b1a1028ad0082752082762864576468821928821a30821b3850103c6d013308015207bc00826c186457821818821920821060821558821650951168320c7b12408178307b18087c79387b19827920827628481730307b1710461738017b194864976468821928821a30821b3850103e1901520767821740c97505955501019555ff5105c600826920330830821748b49001405107ec28435219021298a90195a8019888017b1810280864a9491110018278207b18488276288177307b1740959501019555ff510527826920821748821840b49001425107ed330801016487821060821558821650951168320082154864576468821928821a30821b3850104489003308015207d8826a186457821818821920b4a001463308015207c38217109a777b17383305ff01821738c857075117ff42826920821748821840b49001489555015107e62837826a18821748821818821920b4a0014a33080152078233088217108219087a79308219787938286fff821510821710d875082863ff821710d87508285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c0014c821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b175033073001017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307387b1710017b18207b19288259510917821a588217508258f882aa18b4a0014e52074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49001505207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a001525207568257825908951830b4900154520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0015651070833070128053307018210800082157882167095118800320089284952494a112992254952522a922549525212a284a410d1889224a58814c99224292915c99224292909514252886844499252448a64499294948a6449929494842821294434222228211221111121094952a54910c2922cb510499224211189100911912a4d02212c91a526092029012425499244221189484422422249444244a44a93208425596a1224499284442442244444aa3409425892a5262522224a92a492244912294b511240324d922649254914429648922895104a924220294912429624494a4d21644992a4d4905252856449969a3225494992549224492265299404904c93a4499252599224294949299342c892244929a4b2a490a4a424e9859084b0244b559294524a0a25254955a194241525a542999424492289a424912492484a22492489249229294991b224a92a94922451925a49922449924a96a4a4544a2b4992ac24495227494a82242488102c4992244924494a5292924412499284a4243592a4929094a449422a92a42449928424494a4b92242929892429499224449254929048499294242591482509493291245224496592249324912c494a2509494a2249c924924452924452929224499224852aa914a524a992a42649114924491212894a9224254926254922922449892449aa522649224992aa94499294442449122529494a923225492225912449525249495212498d2402") + # + # # t = reverse_bits_32(8) + # # tt = '{:08b}'.format(t) + # # ttt = count_leading_zeroes(t, 32) + # # print(t, tt, ttt) + # # import pdb;pdb.set_trace() + # + # # t = 15 + # # tt = '{:08b}'.format(t) + # # ttt = count_trailing_zeroes(t, 32) + # # print(t, tt, ttt) + # # import pdb;pdb.set_trace() + # + # + # bootstrap_service_account = await client.serviceData(block_hash, bootstrap_service_id) + # + # work_package.items.append(WorkItem( + # service=bootstrap_service_id, + # code_hash=bootstrap_service_account.code_hash, + # payload=blake2b_256_hash(core_vm_blob) + int(len(core_vm_blob)).to_bytes(length=4, byteorder='little'), + # refine_gas_limit=6000, + # accumulate_gas_limit=6000, + # import_segments=[], + # extrinsic=[], + # export_count=0 + # )) + + new_service = await client.subscribeServiceValue(0, bytes.fromhex("81e47a19e6b29b0a65b9591762ce5143ed30d0261e5d24a3201752506b20f15c")) + async for data in new_service: + corevm_service_id = int.from_bytes(data, byteorder='little') + #print("subscribeServiceValue UPDATE: ", corevm_service_id) + break + print(f"core_vm service id = {corevm_service_id}") + + await client.submitPreimage(corevm_service_id, core_vm_blob, block_hash) + print("corevm preimage submitted") + + new_preimage = await client.subscribeServiceRequest(block_hash, corevm_service_id, blake2b_256_hash(core_vm_blob), len(core_vm_blob)) + async for data in new_preimage: + print("subscribeServiceRequest UPDATE: ", data) + if data is not None and len(data) == 1: + break + print("corevm preimage available") + + + # CoreVM service is activated, create a new workpackage for corevm and provide corevm_child code blob + work_package = await create_bootservice_workpackage(client) + block_hash = work_package.context.anchor + extrinsic = blake2b_256_hash(core_vm_child_blob) + int(len(core_vm_child_blob)).to_bytes( + length=4, byteorder='little' + ) + work_package.items.append( + WorkItem( + service=corevm_service_id, + code_hash=blake2b_256_hash(core_vm_blob), + payload=b'', + refine_gas_limit=6000, + accumulate_gas_limit=6000, + import_segments=[], + extrinsic=[ + WorkItemExtrinsic.from_blob(extrinsic) + ], + export_count=0 + ) + ) + + await client.submitWorkPackage(0, work_package, [extrinsic]) + print("core_vm_child workpackage submitted") + + + new_preimage = await client.subscribeServiceRequest(block_hash, corevm_service_id, blake2b_256_hash(core_vm_child_blob), len(core_vm_child_blob)) + async for data in new_preimage: + print("subscribeServiceRequest UPDATE: ", data) + if data is not None and len(data) == 0: + break + print("core_vm_child preimage requested") + + + await client.submitPreimage(corevm_service_id, core_vm_child_blob, block_hash) + print("corevm preimage submitted") + + + new_preimage = await client.subscribeServiceRequest(block_hash, corevm_service_id, blake2b_256_hash(core_vm_child_blob), len(core_vm_child_blob)) + async for data in new_preimage: + print("subscribeServiceRequest UPDATE: ", data) + if data is not None and len(data) == 1: + break + print("core_vm_child preimage available") + + work_package = await create_bootservice_workpackage(client) + block_hash = work_package.context.anchor + extrinsic = blake2b_256_hash(core_vm_child_blob) + int(len(core_vm_child_blob)).to_bytes( + length=4, byteorder='little' + ) + work_package.items.append( + WorkItem( + service=corevm_service_id, + code_hash=blake2b_256_hash(core_vm_blob), + payload=bytes.fromhex("00000000010000000000000001000000"), + refine_gas_limit=5678, + accumulate_gas_limit=9876, + import_segments=[], + extrinsic=[ + WorkItemExtrinsic.from_blob(extrinsic) + ], + export_count=1 + ) + ) + + await client.submitWorkPackage(0, work_package, [extrinsic]) + print("core_vm trigger corevm child vm") + """ + + print("FIN!!!!!!!!") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/pyjamaz/rpc/interface.py b/pyjamaz/transport/rpc/interface.py similarity index 100% rename from pyjamaz/rpc/interface.py rename to pyjamaz/transport/rpc/interface.py diff --git a/pyjamaz/transport/rpc/parity_playbook.py b/pyjamaz/transport/rpc/parity_playbook.py new file mode 100644 index 00000000..65102132 --- /dev/null +++ b/pyjamaz/transport/rpc/parity_playbook.py @@ -0,0 +1,301 @@ +import asyncio +from typing import List + +from pyjamaz.hashing import blake2b_256_hash +from pyjamaz.models.builder import Instruction +from pyjamaz.models.common import Authorizer, RefinementContext, WorkPackage, WorkItem, WorkItemExtrinsic +from pyjamaz.pvm.types import PVMProgram +from pyjamaz.transport.rpc.ws_client import WebsocketClient + + +async def create_bootservice_workpackage(client, instruction: Instruction, extrinsic: List[bytes]): + best_block = await client.bestBlock() + block_hash = best_block["header_hash"] + block_timeslot = best_block["slot"] + # block_hash = best_block[0] + # block_timeslot = best_block[1] + + state_root = await client.stateRoot(block_hash) + beefy_root = await client.beefyRoot(block_hash) + + authorizer = Authorizer( + code_hash=bytes.fromhex('4c4e4f63481b4b2b4726611dee56d0d8d1a3e163808b3ef678ab25dfa7c32419'), + params=b'' + ) + + context = RefinementContext( + anchor=block_hash, + state_root=state_root, + beefy_root=beefy_root, + lookup_anchor=block_hash, + lookup_anchor_slot=block_timeslot, + prerequisites=[] + ) + + work_package = WorkPackage( + authorization=b'', + auth_code_host=0, + authorizer=authorizer, + context=context, + items=[ + WorkItem( + accumulate_gas_limit=10000000, + code_hash=bytes.fromhex('7d952fd5905548e08a9a7d8fca521139f7e2573a2207d6a6d0e706a13070487b'), + export_count=0, + extrinsic=[WorkItemExtrinsic.from_blob(e) for e in extrinsic], + import_segments=[], + payload=instruction.to_jam_bytes().to_bytes(), + refine_gas_limit=5000000000, + service=0 + ) + ] + ) + + return work_package + + + +async def main(): + + async with WebsocketClient("ws://127.0.0.1:19800") as client: + + bootstrap_service_id = 0 + + # Check storage item + #new_service_id = await client.serviceValue(bytes(32), bootstrap_service_id, b'created') + #services = await client.serviceValue(bytes(32), bootstrap_service_id, b'\x10service_registry') + #print(services) + + # created_key = blake2b_256_hash(int(bootstrap_service_id).to_bytes(length=4, byteorder="little") + b'created') + + create_instruction = Instruction.from_json( + { + 'CreateService': { + 'code_hash': '0x0b77f392fed2d02b19a885627ffc96123394881a44fbb535af31fc3ba8394a74', + 'code_len': 11, + 'endowment': 100000, + 'memo': '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + 'min_item_gas': 1000000, + 'min_memo_gas': 1000000, + 'registration': 'Arie' + } + } + ) + + # core_vm_child_blob = bytes.fromhex( + # "080200080000020000a0004348494c44204e4f524d206e3d206669625f6e5f323d20726573756c743d202861646472323d202861646472313d29206669625f6e5f313d2920726573756c743d4348494c442042415345206e3d4348494c44205752495445206f75745f616464726573733d00003078303030313032303330343035303630373038303931303131313231333134313531363137313831393230323132323233323432353236323732383239333033313332333333343335333633373338333934303431343234333434343534363437343834393530353135323533353435353536353735383539363036313632363336343635363636373638363937303731373237333734373537363737373837393830383138323833383438353836383738383839393039313932393339343935393639373938393900000000000000000100000000000d000000000000000d0001000000000009000000000000001e0001000000000008000000000000002e000100000000000a00000000000000260001000000000008000000000000003800010000000000090000000000000041000100000000000d00000000000000160001000000000008000000000000004e000100000000001800000000000000160001000000000008000000000000001e0000000000000018000000000000000800000000000000200000000000000026000000000000002e000000000000004b598638d6c56d349b10000027028e790300b700c2007601e401ff01cd02e8025e0379030e04a604c5059806bc06ef0619073e0745076f0725084b0852080709190acb0a1e0b3f0b820bae0bc30bec0b040c5e0c130dac0d0b0e1a0e5e0e288101951178ff7b108000808934849a10520a168499205209518077821080009511880028e708817b3309810095177f33025701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842817b3309810095177f33023701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a013309026487330868000150100475098210800095118800320000951178ff7b108000808934849a10520a1684992052095182778210800095118800282808827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a0133090264873308680001501008b6088210800095118800320000951100ff7b10f8007b15f0007b16e800491108ffef7b1710330a027b1a551702940048111c019517107b17403307067b174895171c7b17507b1a5833079801017b177049117802492190009517407b17800049218800029517d00095187050100a14048215d800821be0008216d00033070233083309645a33000c0a6401821708c86707532700f00e01330710000395770010018278c98709ab59f900c9680901827aab8af17b79330b01ab8ae928e40097770c140800e0fefe00000000c878087b182081887a182c140900f0fefe00000000c897077b173081777a173cbe87077a171c9517107b17703307067b177895182c7b1880007b1a88009518207b1890007b17980095183c7b18a0007b1aa8009518307b18b0007b17b80095171c7b17c0007b1ac80033073801017b1740491148064911609518707b1850491158069517d00095184050100e2b038215d800821be0008216d00033070233083309645a3300100a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0181171097770c83770000fffe7a17309517307b174082187b184895171c7b17507b18583307b801017b177049117802492190009518407b18800049218800029517d0009518705010129a028215d800821be0008216d00033070233083309645a3300140a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0180173081181c7a78801730330800108210f8008215f0008216e8009511000132009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101632821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086e82a70851077182a91051099e0082a8330200103304100003c8240701827ac86a05aca5c200955b0188bc01d8b20bd4cb0b520bb200827bababe57b75330c7b1318c95407957700107b17107b180864957b14501018b40354250010940082131882181033077b380828b10049130833070128a800330700103302100003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302100003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101a7cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b1620828a086475510a3582893307959b080182bcc8c70795aaff95bb10520af5828a18510a248299088e99887a1085aa01d4a909897ae0a90952090a3307330901284b977701015107415707746453330900103302100003c8920b0182bcc87c0aacca5b95a501885601d85905d4650552054c82b6abc6e77bbac9a209330a0010c8a90964352806330901017b177b1908491110641750101c030652072282171082180882197b57107b58087b5982103082152882162095113832000000008272330900f0952affefac9a2782770833091000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950102241018217c876067b56103307821018821510821608951120320064577b1864a864695010248cfc8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a550102811fe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950102a34c8560682177b7610013307821020821518821610951128320064a76458646964a550102c7ffb645a82551028c42844049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a87b10507b15487b16407b18987904330827330a6a0001532971027b330827951b3e3a090000037b1910491108f0d80033037b143300ffe0f505016472821710d6720798770b821908c09709c82906976930989932ca39099894119899108499fe07964c9cc86c0c97cc3198cc30c8a9097c967c9901c8ac0c7cc5017ccc78b9ff78b6fe78b50178bc9588fc95bbfcac20ac5417633697793098993296997b14989911969b9cc8b7079777319877309588fec8a7077c7b017c77951c19c88c0c78cb0178c764970155170a149588ff951919c889098377307897281c9777019588fec8a7077c79017c77951a19c88a0a78a90178a701951a19c88a0a9a8b273308680001821733095010321282105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208507c7638c94a0a7b19185a16019d005206aa007b1a1028a90082752082762864576468821a38821b305010346c013308015207bb00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b305010361901520767821740c95705955501019555ff5105c600826920330830821748b49001385107ec28435216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510627825920821748821840b490013a5107ed330801016487821060821558821650951168320082164864676458821918821a38821b3050103c89003308015207d8825a186467821820821928b4a0013e3308015207c38217109a777b17383306ff01821738c867075117ff42825920821748821840b49001409566015107e62837826a18821748821820821928b4a00142330801520782330882168217107a6730821708786738286fff821610821710d876082863ff821710d87608285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c00144821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b17503307d801017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307307b1710017b18207b19288259510917821a588217508258f882aa18b4a0014652074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49001485207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a0014a5207568257825908951830b490014c520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0014e5107083307012805330701821080008215788216709511880032008948921491225992242525214a45b224494a4a42942984884624498a48912c4992929210a522599224252521ca1442442322425288244912129108911011a9d22408b144969a2480a404909424491291884424221121912422212252a54908b1244b4d82242549484422444244a44a93106249969a9488882849924a922449a42c454900c934499a24952451842c9124512a89a44290942489902549925253842c4992949a282555244bb2d49429494a92a492244912294ba12480649a244d9294ca922449494a4a9914214b9224a5442a4b0a494a4a925e4412624996aa2429a594144a4a92aa4229492a4a4a85322949924412494922492491944492481249245352922265495255282549a224b59224499224952c4949a994569224594992a44e9292109290208225499224892449494a529248224992a4243592a492a4244d122a92a424494a42922425a564499224942449921049524948a424494a499244914a42924c24891449529924c92449244b92524942929248523289249194249154922449922449a14a2a452949aa24a94952441249928444a2922449499249499288244952224992aa9449924892a42a6592242511499244494a9292a44c4992484924499294545292944452238900" + # ) + # program = PVMProgram.from_serialized_bytes(core_vm_child_blob, b'', b'') + #core_vm_child_code = bytes.fromhex('27028e790300b700c2007601e401ff01cd02e8025e0379030e04a604c5059806bc06ef0619073e0745076f0725084b0852080709190acb0a1e0b3f0b820bae0bc30bec0b040c5e0c130dac0d0b0e1a0e5e0e288101951178ff7b108000808934849a10520a168499205209518077821080009511880028e708817b3309810095177f33025701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842817b3309810095177f33023701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a013309026487330868000150100475098210800095118800320000951178ff7b108000808934849a10520a1684992052095182778210800095118800282808827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a0133090264873308680001501008b6088210800095118800320000951100ff7b10f8007b15f0007b16e800491108ffef7b1710330a027b1a551702940048111c019517107b17403307067b174895171c7b17507b1a5833079801017b177049117802492190009517407b17800049218800029517d00095187050100a14048215d800821be0008216d00033070233083309645a33000c0a6401821708c86707532700f00e01330710000395770010018278c98709ab59f900c9680901827aab8af17b79330b01ab8ae928e40097770c140800e0fefe00000000c878087b182081887a182c140900f0fefe00000000c897077b173081777a173cbe87077a171c9517107b17703307067b177895182c7b1880007b1a88009518207b1890007b17980095183c7b18a0007b1aa8009518307b18b0007b17b80095171c7b17c0007b1ac80033073801017b1740491148064911609518707b1850491158069517d00095184050100e2b038215d800821be0008216d00033070233083309645a3300100a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0181171097770c83770000fffe7a17309517307b174082187b184895171c7b17507b18583307b801017b177049117802492190009518407b18800049218800029517d0009518705010129a028215d800821be0008216d00033070233083309645a3300140a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0180173081181c7a78801730330800108210f8008215f0008216e8009511000132009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101632821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086e82a70851077182a91051099e0082a8330200103304100003c8240701827ac86a05aca5c200955b0188bc01d8b20bd4cb0b520bb200827bababe57b75330c7b1318c95407957700107b17107b180864957b14501018b40354250010940082131882181033077b380828b10049130833070128a800330700103302100003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302100003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101a7cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b1620828a086475510a3582893307959b080182bcc8c70795aaff95bb10520af5828a18510a248299088e99887a1085aa01d4a909897ae0a90952090a3307330901284b977701015107415707746453330900103302100003c8920b0182bcc87c0aacca5b95a501885601d85905d4650552054c82b6abc6e77bbac9a209330a0010c8a90964352806330901017b177b1908491110641750101c030652072282171082180882197b57107b58087b5982103082152882162095113832000000008272330900f0952affefac9a2782770833091000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950102241018217c876067b56103307821018821510821608951120320064577b1864a864695010248cfc8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a550102811fe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950102a34c8560682177b7610013307821020821518821610951128320064a76458646964a550102c7ffb645a82551028c42844049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a87b10507b15487b16407b18987904330827330a6a0001532971027b330827951b3e3a090000037b1910491108f0d80033037b143300ffe0f505016472821710d6720798770b821908c09709c82906976930989932ca39099894119899108499fe07964c9cc86c0c97cc3198cc30c8a9097c967c9901c8ac0c7cc5017ccc78b9ff78b6fe78b50178bc9588fc95bbfcac20ac5417633697793098993296997b14989911969b9cc8b7079777319877309588fec8a7077c7b017c77951c19c88c0c78cb0178c764970155170a149588ff951919c889098377307897281c9777019588fec8a7077c79017c77951a19c88a0a78a90178a701951a19c88a0a9a8b273308680001821733095010321282105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208507c7638c94a0a7b19185a16019d005206aa007b1a1028a90082752082762864576468821a38821b305010346c013308015207bb00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b305010361901520767821740c95705955501019555ff5105c600826920330830821748b49001385107ec28435216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510627825920821748821840b490013a5107ed330801016487821060821558821650951168320082164864676458821918821a38821b3050103c89003308015207d8825a186467821820821928b4a0013e3308015207c38217109a777b17383306ff01821738c867075117ff42825920821748821840b49001409566015107e62837826a18821748821820821928b4a00142330801520782330882168217107a6730821708786738286fff821610821710d876082863ff821710d87608285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c00144821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b17503307d801017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307307b1710017b18207b19288259510917821a588217508258f882aa18b4a0014652074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49001485207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a0014a5207568257825908951830b490014c520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0014e5107083307012805330701821080008215788216709511880032008948921491225992242525214a45b224494a4a42942984884624498a48912c4992929210a522599224252521ca1442442322425288244912129108911011a9d22408b144969a2480a404909424491291884424221121912422212252a54908b1244b4d82242549484422444244a44a93106249969a9488882849924a922449a42c454900c934499a24952451842c9124512a89a44290942489902549925253842c4992949a282555244bb2d49429494a92a492244912294ba12480649a244d9294ca922449494a4a9914214b9224a5442a4b0a494a4a925e4412624996aa2429a594144a4a92aa4229492a4a4a85322949924412494922492491944492481249245352922265495255282549a224b59224499224952c4949a994569224594992a44e9292109290208225499224892449494a529248224992a4243592a492a4244d122a92a424494a42922425a564499224942449921049524948a424494a499244914a42924c24891449529924c92449244b92524942929248523289249194249154922449922449a14a2a452949aa24a94952441249928444a2922449499249499288244952224992aa9449924892a42a6592242511499244494a9292a44c4992484924499294545292944452238900') + + #TODO: + # with open("/Users/matthijsblaas/dev/polkavm/services/corevm_child/corevm_child.pvm", "rb") as ff: + # core_vm_child_blob = ff.read() + # program = PVMProgram.from_serialized_bytes(core_vm_child_blob, b'', b'') + # core_vm_child_code = program.code + # core_vm_child_code = program._code #bytes.fromhex("20028b8d0300b50043015e01e6017e029d03cb03fe0328044d0454047e0434055a05610516062d07df07320853089608c208d708000918097209270ac00a1f0b2e0b720b28c000951178ff7b108000808934849a10520a1484992052094f821080009511880028f805827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a01330902648733080800015010048b068210800095118800320000951178ff7b1080007b15787b16707b17089517087b17403307027b17483307d800017b1710491118014911309518407b182049112801330700103306100003c8760801828a95a910aca99300959b0188bc01d8b70bd4cb0b520b8300828bababe57b89330c7b16c9960795770010491150107b17584911609517509518105010066c08520759821558821b6082165033070233083309645a3300080a64019568ffef532800f022821895870010018278c98709ab5911c9680901827aab8af27b79330b01821708330800108210800082157882167095118800320000009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950100a32821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086e82a70851077182a91051099e0082a8330200103304100003c8240701827ac86a05aca5c200955b0188bc01d8b20bd4cb0b520bb200827bababe57b75330c7b1318c95407957700107b17107b180864957b1450100ceb0254250010940082131882181033077b380828b10049130833070128a800330700103302100003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302100003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950100e7cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200008272330900f0952affefac9a2782770833091000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950101441018217c876067b56103307821018821510821608951120320064577b1864a8646950101655fd8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a550101adafe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950101c34c8560682177b7610013307821020821518821610951128320064a76458646964a550101e48fc645a82551028c42849049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a87b10507b15487b1640827a7b1898ab0433082733090a0001532b71027e330827951b3e3a070000037b1710491108f0d80033007b143303ffe0f50533059c0164a4821710d67a0a98aa0b821708c07a0cc84c06976c3098cc32ca0c0c98c71198cc1084ccfe07ca5707c86707977731987730c89c0c7cc67ccc01c897077c72017c7778bcff78b6fe78b20178b79588fc95bbfcac43ac541a633697a73098773296777b14987711967b9cc8ba0a97aa3198aa309588fec89a0a7cab017caa951c19c88c0c78cb0178ca647a01551a0a149588ff951719c8870783a9307879281c97aa019588fec8a9097c97017c99951a19c88a0a78a70178a901951a19c88a0a9a8b273308080001821733095010241282105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208507c7638c94a0a7b19185a16019d005206aa007b1a1028a90082752082762864576468821a38821b305010266c013308015207bb00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b305010281901520767821740c95705955501019555ff5105c600826920330830821748b490012a5107ec28435216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510627825920821748821840b490012c5107ed330801016487821060821558821650951168320082164864676458821918821a38821b3050102e89003308015207d8825a186467821820821928b4a001303308015207c38217109a777b17383306ff01821738c867075117ff42825920821748821840b49001329566015107e62837826a18821748821820821928b4a00134330801520782330882168217107a6730821708786738286fff821610821710d876082863ff821710d87608285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c00136821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b17503307e800017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307227b1710017b18207b19288259510917821a588217508258f882aa18b4a0013852074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b490013a5207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a0013c5207568257825908951830b490013e520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0014051070833070128053307018210800082157882167095118800320089489244a44896244949498852912c4992929210650a21a211499224249244842c912451aa44244948925469846249969a88243a49924a922449a42c454900c934499a24952451842c9124512a89a44290942489902549925253842c4992949a282555244bb2d49429494a92a492244912294ba12480649a242d2209b1244b559294524a0a25254955a194241525a542999424492289a424912492484a22492489249229294991b224a92a94922451925a49922449924a96a4a4544a2b4992ac24495227492521242141045992244992489294a4242589249224494a5223492a494ad224a122494a92a424244952524a962449424992240991249584444a92a494244914a92424c944924891249549924c9244b22429952424298924259348124949124925499224499214aaa4529492a44a929a24452491244948242a4992942499942489489224259224a94a9924892449aa522649521291244994a4242949ca9424899444922449492525494924359208") + # rom = program._rom #bytes.fromhex('4348494c44206e3d3078303030313032303330343035303630373038303931303131313231333134313531363137313831393230323132323233323432353236323732383239333033313332333333343335333633373338333934303431343234333434343534363437343834393530353135323533353435353536353735383539363036313632363336343635363636373638363937303731373237333734373537363737373837393830383138323833383438353836383738383839393039313932393339343935393639373938393900000000000000000100000000000800000000000000100000000000000018000000000000000800000000000000120000000000000018000000000000002000000000000000') + # ram = program._ram #bytearray(b'KY\x868\xd6\xc5m4') + + core_vm_child_code = bytes(bytearray([0, 0, 33, 51, 8, 1, 51, 9, 1, 40, 3, 0, 149, 119, 255, 81, 7, 12, 100, 138, 200, 152, 8, 100, 169, 40, 243, + 100, 135, 51, 8, 51, 9, 1, 50, 0, 73, 147, 82, 213, 0])) + rom = bytes(4096) + ram = bytes(4096) + + extrinsic = [core_vm_child_code, rom, ram] + # extrinsic = [] + + work_package = await create_bootservice_workpackage(client, create_instruction, extrinsic) + # work_package = await create_bootservice_workpackage(client, create_instruction, []) + + await client.submitWorkPackage(0, work_package, extrinsic) + print("WORKPACKAGE SUBMITTED") + + new_service = await client.subscribeServiceValue(bootstrap_service_id, b'created') + async for data in new_service: + print("SUBSCRIPTION RECEIVED DATA", data) + if data: + new_service_id = int.from_bytes(data, byteorder='little') + print(new_service_id) + break + + + """ + + bootstrap_service_id = 0 + + # Check storage item + new_service_id = await client.serviceValue(bytes(32), bootstrap_service_id, b'created') + services = await client.serviceValue(bytes(32), bootstrap_service_id, b'\x10service_registry') + print(services) + + create_instruction = Instruction.from_json( + { + 'CreateService': { + 'code_hash': '0x0b77f392fed2d02b19a885627ffc96123394881a44fbb535af31fc3ba8394a74', + 'code_len': 11, + 'endowment': 100000, + 'memo': '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + 'min_item_gas': 1000000, + 'min_memo_gas': 1000000, + 'registration': 'Arie' + } + } + ) + + transfer_instruction = Instruction.from_json({'Transfer': { + 'destination': 3081892978, + 'amount': 66666666, + 'gas_limit': 1000000, + 'memo': '0x0102030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + }}) + + random_storage_instruction = Instruction.from_json({'RandomStorageRefine': { + 'seed': 3081892978, + 'nb_items': 6 + }}) + + export_instruction = Instruction.from_json( + {'Export': { + 'data': [b'test'], + }} + ) + + zombify_instruction = Instruction.from_json({'Zombify': {'ejector': 0}}) + + eject_instruction = Instruction.from_json({'Eject': {'target': 0, 'code_hash': '0x6c63e601e26279872a93b9b443aa52ad1c26e795647f63c0b7e0abff0d3680da'}}) + + core_vm_child_blob = bytes.fromhex("080200080000020000a0004348494c44204e4f524d206e3d206669625f6e5f323d20726573756c743d202861646472323d202861646472313d29206669625f6e5f313d2920726573756c743d4348494c442042415345206e3d4348494c44205752495445206f75745f616464726573733d00003078303030313032303330343035303630373038303931303131313231333134313531363137313831393230323132323233323432353236323732383239333033313332333333343335333633373338333934303431343234333434343534363437343834393530353135323533353435353536353735383539363036313632363336343635363636373638363937303731373237333734373537363737373837393830383138323833383438353836383738383839393039313932393339343935393639373938393900000000000000000100000000000d000000000000000d0001000000000009000000000000001e0001000000000008000000000000002e000100000000000a00000000000000260001000000000008000000000000003800010000000000090000000000000041000100000000000d00000000000000160001000000000008000000000000004e000100000000001800000000000000160001000000000008000000000000001e0000000000000018000000000000000800000000000000200000000000000026000000000000002e000000000000004b598638d6c56d349b10000027028e790300b700c2007601e401ff01cd02e8025e0379030e04a604c5059806bc06ef0619073e0745076f0725084b0852080709190acb0a1e0b3f0b820bae0bc30bec0b040c5e0c130dac0d0b0e1a0e5e0e288101951178ff7b108000808934849a10520a168499205209518077821080009511880028e708817b3309810095177f33025701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842817b3309810095177f33023701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a013309026487330868000150100475098210800095118800320000951178ff7b108000808934849a10520a1684992052095182778210800095118800282808827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a0133090264873308680001501008b6088210800095118800320000951100ff7b10f8007b15f0007b16e800491108ffef7b1710330a027b1a551702940048111c019517107b17403307067b174895171c7b17507b1a5833079801017b177049117802492190009517407b17800049218800029517d00095187050100a14048215d800821be0008216d00033070233083309645a33000c0a6401821708c86707532700f00e01330710000395770010018278c98709ab59f900c9680901827aab8af17b79330b01ab8ae928e40097770c140800e0fefe00000000c878087b182081887a182c140900f0fefe00000000c897077b173081777a173cbe87077a171c9517107b17703307067b177895182c7b1880007b1a88009518207b1890007b17980095183c7b18a0007b1aa8009518307b18b0007b17b80095171c7b17c0007b1ac80033073801017b1740491148064911609518707b1850491158069517d00095184050100e2b038215d800821be0008216d00033070233083309645a3300100a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0181171097770c83770000fffe7a17309517307b174082187b184895171c7b17507b18583307b801017b177049117802492190009518407b18800049218800029517d0009518705010129a028215d800821be0008216d00033070233083309645a3300140a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0180173081181c7a78801730330800108210f8008215f0008216e8009511000132009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101632821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086e82a70851077182a91051099e0082a8330200103304100003c8240701827ac86a05aca5c200955b0188bc01d8b20bd4cb0b520bb200827bababe57b75330c7b1318c95407957700107b17107b180864957b14501018b40354250010940082131882181033077b380828b10049130833070128a800330700103302100003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302100003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101a7cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b1620828a086475510a3582893307959b080182bcc8c70795aaff95bb10520af5828a18510a248299088e99887a1085aa01d4a909897ae0a90952090a3307330901284b977701015107415707746453330900103302100003c8920b0182bcc87c0aacca5b95a501885601d85905d4650552054c82b6abc6e77bbac9a209330a0010c8a90964352806330901017b177b1908491110641750101c030652072282171082180882197b57107b58087b5982103082152882162095113832000000008272330900f0952affefac9a2782770833091000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950102241018217c876067b56103307821018821510821608951120320064577b1864a864695010248cfc8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a550102811fe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950102a34c8560682177b7610013307821020821518821610951128320064a76458646964a550102c7ffb645a82551028c42844049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a87b10507b15487b16407b18987904330827330a6a0001532971027b330827951b3e3a090000037b1910491108f0d80033037b143300ffe0f505016472821710d6720798770b821908c09709c82906976930989932ca39099894119899108499fe07964c9cc86c0c97cc3198cc30c8a9097c967c9901c8ac0c7cc5017ccc78b9ff78b6fe78b50178bc9588fc95bbfcac20ac5417633697793098993296997b14989911969b9cc8b7079777319877309588fec8a7077c7b017c77951c19c88c0c78cb0178c764970155170a149588ff951919c889098377307897281c9777019588fec8a7077c79017c77951a19c88a0a78a90178a701951a19c88a0a9a8b273308680001821733095010321282105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208507c7638c94a0a7b19185a16019d005206aa007b1a1028a90082752082762864576468821a38821b305010346c013308015207bb00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b305010361901520767821740c95705955501019555ff5105c600826920330830821748b49001385107ec28435216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510627825920821748821840b490013a5107ed330801016487821060821558821650951168320082164864676458821918821a38821b3050103c89003308015207d8825a186467821820821928b4a0013e3308015207c38217109a777b17383306ff01821738c867075117ff42825920821748821840b49001409566015107e62837826a18821748821820821928b4a00142330801520782330882168217107a6730821708786738286fff821610821710d876082863ff821710d87608285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c00144821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b17503307d801017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307307b1710017b18207b19288259510917821a588217508258f882aa18b4a0014652074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49001485207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a0014a5207568257825908951830b490014c520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0014e5107083307012805330701821080008215788216709511880032008948921491225992242525214a45b224494a4a42942984884624498a48912c4992929210a522599224252521ca1442442322425288244912129108911011a9d22408b144969a2480a404909424491291884424221121912422212252a54908b1244b4d82242549484422444244a44a93106249969a9488882849924a922449a42c454900c934499a24952451842c9124512a89a44290942489902549925253842c4992949a282555244bb2d49429494a92a492244912294ba12480649a244d9294ca922449494a4a9914214b9224a5442a4b0a494a4a925e4412624996aa2429a594144a4a92aa4229492a4a4a85322949924412494922492491944492481249245352922265495255282549a224b59224499224952c4949a994569224594992a44e9292109290208225499224892449494a529248224992a4243592a492a4244d122a92a424494a42922425a564499224942449921049524948a424494a499244914a42924c24891449529924c92449244b92524942929248523289249194249154922449922449a14a2a452949aa24a94952441249928444a2922449499249499288244952224992aa9449924892a42a6592242511499244494a9292a44c4992484924499294545292944452238900") + + extrinsic = [core_vm_child_blob] + + work_package = await create_bootservice_workpackage(client, create_instruction, extrinsic) + + await client.submitWorkPackage(0, work_package, extrinsic) + print("Workpackage submitted") + exit() + + # block_hash = work_package.context.anchor + # + # core_vm_blob = bytes.fromhex("06636f7265766d481200180000020000a0008c00ffffa400ffffb600ffffc800ffffe000fffff800ffff0e01ffff1a01ffff2601ffff3801ffff0010000000000000fcfffffffffffffffaffffffffffffff657870756e6765200000000000000000ffffffffffffffff206f75747075743df7ffffffffffffff7a3d20733d206f5f62797465735f616464726573733d20635f62797465735f6c656e6774683d696e666f3a20657870656374204f4b20206f5f62797465735f6c656e6774683d20775f62797465735f6c656e6774683d3a2065787065637420cf822b7c657c3d3a20696e7365727420742c20676f74207969656c642c20657870656374204f4b20775f62797465735f616464726573733d20635f62797465735f616464726573733d6761735f726573756c743d6d616368696e65206e657720696e6465783d6665746368207365676d656e745f696e6465783d2066657463685f726573756c743d7a65726f206d3d2c20706167655f69643d207a65726f5f726573756c743d706f6b65206d3d206f3d207a3d20706f6b655f726573756c743d7a65726f20666f7220726573756c74206d3d6265666f7265206368696c645f766d5f7265676973746572733d696e766f6b652020696e766f6b655f726573756c743d206761733d6f75747075745f62797465733d7c3a206368696c6420564d20696e737472756374696f6e20636f756e7465723d7065656b206368696c645f766d5f69643d2c207365676d656e745f6275665f706167655f616464726573733d2c206368696c645f706167655f616464726573733d20504147455f53495a453d207065656b5f726573756c743d207365676d656e745f6275665b302e2e385d3d2c206368696c645f69643d2c207365675f696e6465783d6578706f727420693d2c20676f7420726561642066726f6d206a616d3a20657870656374204e4f4e452020287265636f72646564206174206b6579203129777269746520746f206a616d3a20657870656374204e4f4e452020287265636f72646564206174206b6579203229726561642066726f6d206a616d3a20657870656374204f4b2020287265636f72646564206174206b6579203529666f72676574206a616d3a20657870656374204855482020287265636f72646564206174206b657920362972656164206a616d3a20657870656374204f4b2077726974652064656c65746564206a616d3a206578706563742070726576206c656e20332c20676f742072656164206a616d3a20657870656374204e4f4e4520736f6c696369742068617368286a616d293a20657870656374204f4b2071756572792068617368286a616d293a20657870656374206e6f6e2d5a45524f2c20676f74207175657279206861736828646f74293a20657870656374204e4f4e4520666f726765742068617368286a616d293a20657870656374204f4b2071756572792068617368286a616d293a20657870656374206e6f6e2d7a65726f2c20676f74206c6f6f6b7570206861736828646f74293a20657870656374204e4f4e452061737369676e206a616d3a2065787065637420434f5245206c6f6f6b75702068617368286a616d293a20657870656374204f4b2071756572792068617368286a616d293a20657870656374204f4b20656a6563743a206578706563742057484f20626c6573733a206578706563742057484f20736f6c696369742068617368286a616d292c20657870656374204f4b2061737369676e3a20657870656374204f4b202028322b325e33322a78292c20676f74206c6f6f6b75702068617368286a616d292c20657870656374204f4b203a20332028322b325e33322a78292c20676f74206e65773a20657870656374204f4b202028736572766963655f696e646578292c20676f7420757067726164653a20657870656374204f4b20626c6573733a20657870656374204f4b2077726974652064656c6574656420444f543a20657870656374204e4f4e4520777269746520746f20444f543a20657870656374204e4f4e452077726974652064656c6574656420444f543a206578706563742070726576206c656e20332c20676f7420726561642066726f6d20444f543a20657870656374204e4f4e452020287265636f72646564206174206b657920372920287265636f72646564206174206b65792038296761733a20676f742020287265636f72646564206174206b6579203929636f7265766d20636865636b706f696e746f6e5f7472616e73666572206761733a20676f742020287265636f72646564206174206b6579203429005b696e666f726561647065656b7a65726f20202020706f6b652c202c0a0a5d307830303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839395374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20737563636573735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f72206f5f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220737461636b5374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f72206f5f627974657377726974655f726573756c74206b65793d2c20726573756c743d000000680001000000000002000000000000006a0001000000000003000000000000006d0001000000000011000000000000009e000100000000001000000000000000ee000100000000001100000000000000ae000100000000001000000000000000ff0001000000000011000000000000007e00010000000000100000000000000010010100000000000b000000000000001b0101000000000012000000000000002d01010000000000140000000000000041010100000000000e000000000000004f01010000000000070000000000000056010100000000000a0000000000000060010100000000000d000000000000006d0101000000000007000000000000006a00010000000000030000000000000074010100000000000300000000000000770101000000000003000000000000007a010100000000000d000000000000008701010000000000120000000000000056010100000000000a0000000000000060010100000000000d0000000000000099010100000000001a00000000000000b3010100000000000700000000000000ba010100000000000f00000000000000c9010100000000000500000000000000ce010100000000000d00000000000000db010100000000000100000000000000db01010000000000010000000000000040000100000000000800000000000000dc010100000000001f00000000000000c9010100000000000500000000000000fb0101000000000011000000000000000c020100000000001b00000000000000270201000000000015000000000000003c020100000000000b0000000000000047020100000000000d000000000000005402010000000000130000000000000067020100000000000b0000000000000072020100000000000c000000000000007e020100000000000900000000000000be00010000000000100000000000000087020100000000000600000000000000c9010100000000000500000000000000580001000000000008000000000000008d020100000000001b0000000000000087020100000000000600000000000000a8020100000000001400000000000000bc020100000000001a0000000000000087020100000000000600000000000000d6020100000000001400000000000000ea020100000000001900000000000000870201000000000006000000000000000303010000000000140000000000000017030100000000001700000000000000870201000000000006000000000000002e0301000000000014000000000000004203010000000000140000000000000087020100000000000600000000000000a802010000000000140000000000000056030100000000002a00000000000000d602010000000000140000000000000080030100000000001600000000000000870201000000000006000000000000000303010000000000140000000000000096030100000000001d0000000000000087020100000000000600000000000000a8020100000000001400000000000000b3030100000000002600000000000000d6020100000000001400000000000000d9030100000000001d000000000000008702010000000000060000000000000003030100000000001400000000000000f6030100000000001c0000000000000087020100000000000600000000000000a802010000000000140000000000000012040100000000002600000000000000d602010000000000140000000000000038040100000000001e00000000000000870201000000000006000000000000000303010000000000140000000000000056040100000000001800000000000000870201000000000006000000000000002e0301000000000014000000000000006e040100000000001c0000000000000087020100000000000600000000000000a80201000000000014000000000000008a040100000000001b0000000000000087020100000000000600000000000000d6020100000000001400000000000000a50401000000000012000000000000008702010000000000060000000000000003030100000000001400000000000000b7040100000000001200000000000000870201000000000006000000000000002e030100000000001400000000000000c9040100000000001d00000000000000ce000100000000001000000000000000a8020100000000001400000000000000e604010000000000120000000000000087020100000000000600000000000000030301000000000014000000000000008a040100000000001b00000000000000f8040100000000001100000000000000a802010000000000140000000000000009050100000000001c0000000000000025050100000000001400000000000000a80201000000000014000000000000008a040100000000001b00000000000000f8040100000000001100000000000000d602010000000000140000000000000039050100000000000f0000000000000048050100000000001600000000000000a80201000000000014000000000000005e05010000000000130000000000000087020100000000000600000000000000d602010000000000140000000000000071050100000000001100000000000000870201000000000006000000000000000303010000000000140000000000000082050100000000001f0000000000000087020100000000000600000000000000a8020100000000001400000000000000a1050100000000001a0000000000000087020100000000000600000000000000a8020100000000001400000000000000bb050100000000002a0000000000000003030100000000001400000000000000e5050100000000001b00000000000000870201000000000006000000000000002e03010000000000140000000000000082050100000000001f0000000000000087020100000000000600000000000000000601000000000014000000000000008e00010000000000100000000000000087020100000000000600000000000000140601000000000014000000000000002806010000000000090000000000000031060100000000001400000000000000560601000000000015000000000000006b06010000000000140000000000000076010000000000001800000000000000080000000000000078010000000000007e010000000000008601000000000000a80100000000000018000000000000000800000000000000aa01000000000000b001000000000000b401000000000000cb080100000000001100000000000000dc08010000000000090000000000000056555555555555554b598638d6c56d348080808080808080604e000080e502c00e440d00c500d000f90024014f01620118022302d902e4029803a303570462048904a404b604c804da04ec04fe04100522053405460558056a057c059c0524067f061d083808a908c40836095109bc0a710b8d0b240c3c0cf40c0c0dae0dca0d710e8c0e940fb30f01104f10cc10eb1022124112ed120813e31302148814a714371553152f1698163f170c193919a519c619031a631a7c1abc1a231b3c1b7a1bcc1be51b181c7c1c9d1cdd1c321d4b1d8c1deb1d041e371e8e1eaf1eef1e401f591f9a1fec1f052042209920ba20fa204a216321a321082221225f22b322cc22ff225f238023bd23172430247024cf24e824262584259d25da25ee253a265b26ea260e274e275e277027db27f32726287e289f28dd282e2947297a29db29fc293a2a8b2aa42ae12a402b612b9e2bfd2b162c562cc92ce22c212d842da52de82d482e612e9f2ef32e0c2f472faf2fc82f043059307230ac30c630123133317331b131ca31183254328e32be32d7325f33f8331835f03514364736723698369f36ca368137a837af37c838db398e3ae23a043b483b753b8b3bb53bce3b2a3cda3c743dd73de73d2c3e473e493ec63e0a4053408340b9402f4149417441dd41f641484361439e43c643df43004428aa050000288b150000286c32951178ff7b1080008089348277849a10520a168499205209527c778210800095118800289c387c77330b810095197f3302570164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe562780006a9abb8100641ac87a0a28437c77330b810095197f3302370164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe56278000289abb8100641ac87a0a01330902648733089f0601501004293982108000951188003200009511c07b10387b15307b16287b18088289288276827508828720829a183308800601330901b4a001088218087b181078171846111951052c3307027b17019567017b17087b1620951710951820821950100aa63f9555ff8216085205e47c17180133080152071e821710827828827720828a1833089e0601330901b4a0010c64780164878210388215308216289511403200951178ff7b1080008089348277849a10520a1684992052095182778210800095118800284737827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a01330902648733089f0601501010d6378210800095118800320000951178ff7b108000808934849a10520a168499205209527c7782108000951188002888367c77330b810095197f3302570164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe562780006a9abb8100641ac87a0a28437c77330b810095197f3302370164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe56278000289abb8100641ac87a0a01330902648733089f060150101415378210800095118800320000951178ff7b108000808934849a10520a168499205209518077821080009511880028c735817b3309810095177f33025701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842817b3309810095177f33023701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a01330902648733089f060150101856368210800095118800320000951178ff7b108000808934849a10520a1684992052095182778210800095118800280835827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a01330902648733089f060150101c973582108000951188003200009511d07b10287b15207b16186485828828825a20828b186476330880060133090164a7b4b001207b157817084611097b161033050e641795181033090e501022263c9567087b171064179518106459501024143c9567107b171064179518106459501026023c9567187b171064179518106459501028f03b9567207b17106417951810645950102ade3b9567287b17106417951810645950102ccc3b9567307b17106417951810645950102eba3b9567387b171064179518106459501030a83b9567407b171064179518106459501032963b9567487b171064179518106459501034843b9567507b171064179518106459501036723b9567587b171064179518106459501038603b9567607b17106417951810645950103a4e3b3307017c180852081a8217827828827720828a1833089e0601330901b4a0013c8210288215208216189511303200951108f87b10f0077b15e8077b16e007951148d4330a000001531804df00958bfc510bd7007d7804807a33060159083d8488ff003306025328c0002d3306035328e000253306045328f0001d3306055328f800153306065328fc000d8888fe009a860801ae6b06287e0f7b1a6895770464687b1b7050103ee53b6475821770e46707c96707d85708e45707c95707887720d4870752075b48219800492190004921880049218000491178951778330924330a033308330b330c0a1201951a78330824531508399517a000330900203308501040f3319518789519a000330b0020821768330a0a11019578015518042b3308330a000001280533080164a73309b82bc891018210f0078215e8078216e0079511f80732009578fd531803d68478fe511806cf9578f8531803c87c18a2007c19a1007c1aa000978810979908d49808d4a8089579f5ac89a97c17a5007c1aa4007c1ba30097771097aa08d4a707d4b707c98909ac798bc97906531604859512ab00c82803c8370b7cbc037cb5027cba7cb90197cc10975508d45c0cd4c909979908d4a90c9566fcacc657ff7c19a700951aa0207c14a6009799087c16aa007c15a900d449047c19a800976610975508d46505d459093305ffef7b157095bb047ba47ba9087ba2107ba8187ba3207ba7287bab307bac387baa5033081a7ba8589517a8207ba7607ba8689517b0207ba7707ba8789517b8207ba780007ba888009517c0207ba790007ba898009517c8207ba7a0007ba8a8009517d0207ba7b0007ba8b8009517d8207ba7c0007b18687ba8c8003307e808019516f8307b6748014926500108492668019518f0207b685801492660010895178831951840325010422e2d82659800826ba0008266900033070233083309645a3300440a6401821770c86707330c400003532700f01e95c70010018278c98709ab590fc9680901827aab8af27b79017b1c600a9518a0207b87409517e0209516f8307b6790008217687b67980033076809017b17187b8750951788317b87604918580149187049186801951740329518f020501046a22c82655001826b58018266480133070233083309645a3300480a6401821770c86707532700f02182186095870010018278c98709ab590fc9680901827aab8af27b79019515a02082573082583833090a147b57489517e8209516f8307b67900033077809017b5750951788317b576049155801491568018217687b679800491570951740329518f02050104a152c82655001826b58018266480133070233083309645a33004c0a6401821770c86707532700f02182186095870010018278c98709ab590fc9680901827aab8af27b79019519a02082977b17488297087b17408297107b17388295188298207b1830809748829628491150ff0f9559ff0f98990c3308107b17580a1701510717330a8d0801330702330b3e330833090a6428e0007b1628821750c8670798770c821948c879097b15489557ffff0084770000ff957500000298580c8217580a1701510717330a4f0801330702330b3e330833090a64289c00821650821740c8760698690c846700f014080000fefe00000000c9780898880c8217580a1701510716330a130801330702330b3c330833090a64285f3309000001821758821838821a480a1601510716330ad50701330702330b3e330833090a6428388217588218306459821a280a1601510716330a970701330702330b3e330833090a642814330a690701330702330b2e330833090a64019516f830330508109517f02033083309081050104eb62d49069517f8207b67084916104916189517f020330a0633087b15586459330b330c0a12017b67680233082800017b18505117ff530233078809017b17483307a809017b17403307d809017b173828279516f830826b95bb017b6b9517f020330a063308821958330c0a12017b6768025117ff14027b6690008217687b679800951860337b68a0007b67a8008217487b674801492650010249266801951888317b68580149266001029517203195184032501050da299517f830827630827b3882752833070233083309646a3300520a6401821770c85707821c6033020010532700f01cc82c088287c97809ab690fc9570901828aab7aef7b89019518a0208087508088549515f8307b57107b58183309010a177b574802951708317b5748018217687b575001951810317b5858017b576001951840337b5868017b5770018217407b57900049259800034925b000951740327b57a0004925a8000395172031951888315010542729825630825b3882552833070233083309646a3300560a640133020010821c60821770c85707532700f01cc82c088287c97809ab690fc9570901828aab7aef7b89019515f8308259188257109518f0207b58780297990c7b598802330a00109518f8200a167b570801951708317b5748018217687b575001951870337b5858017b576001951880337b5868017b5770018218507b5878017b578001951800327b5888017b5790018217387b57900049259800054925b000951740327b57a0004925a8000595172031951888315010585728825630825b3882552833070233083309646a33005a0a640133020010821c60821770c85707532700f0f2fdc82c088287c97809ab69e4fdc9570901828aab7aee7b89330b01ab7ae628cffd826918959a018267103308f0ef0fdb9a087b68183309010a177b6720951708317b674801951710317b675801951718317b6768013307280a017b679000951740327b67a00049269800034926a800038217687b6750017b6760017b6770014926b000951720319518883150105c9d27826530826b389517f83082762833070233083309645a33005e0a6401821770c86707532700f02382186095870010018278c98709ab5911c9680901827aab8af27b79330b019516f83049165849165049164849164049163849167049167814070000ffff000000007b672814070000fefe000000007b6730826749268000492688004916687b6760951720317b67080133071e7b6710013307580a017b674801492650010149266801951700327b67580149266001019517883195184032501060da2682659800826ba0008266900033070233083309645a3300620a6401821770c86707821360532700f01e95370010018278c98709ab590fc9680901827aab8af27b7901951cf83082c72882c83082c93882ca4082cb4882c25082c658492c900000000182c5607bc7980082c7687bc8a00082c8707bc9a80082c9787bcab00082ca80007bcbb80082cb88007bc2c0007bc6c8009516f8307b65d0007b67d8007b68e0007b69e8007b6af0007b6bf8003307680a017b1748953700107b1740019517a020827748951888310a197b18587b6700019517e8207b6748018217687b6750019518f8317b6858017b6760019518e0207b6868017b6770018217487b670801492610010349262801951740327b67180149262001039517803395180032501064b72582659002826b98029517f8308276880233070233083309645a3300660a6401821770c86707821b40532700f01982b7c97b08ab580fc967080182b9ab79f27bb8019516f830826700015107ae00857703821858858864d48707520742ff9517203133096895189031501068bf278267607b17588267687b17288265707b15208267787b1738826780007b173049264001492638014926300149262801492620014926180149261001492608019517403233090001330850106a23289517a02082774895180032821928645a0a159517a02082774895184032821938821530645a0a1595180032951a4032821758821920645b0a6428a7fe0a9518a0207b87409517e0207b6788028217187b674801951780337b675801492650010149266001018217687b67900249266801951700329518403250106c7f2482651001826b18019517f8308276080133070233083309645a33006e0a6401821770c86707532700f02382186095870010018278c98709ab5911c9680901827aab8af27b79330b019517a0208277489516f830482650024926480282697a6754023308127b18487b19405119ffff02330814090000fffe000000007b1938140700f0ffffff0f00007b17303307f80a017b1728491120f0ef0f3307067b17183307167b17103307480b017b170828138219589598019516f830821740aa79ad027b6858027b185897890c9517a020827748826808821a38c8a909821a30d2a9097b696002330a00100a157b6768029517e8207b6748018217687b675001951800317b6858017b676001951858337b6868017b6770018218507b6878017b678001951860337b6888017b6790018217287b670801492610010549262801951840327b68180149262001059517803395180032501070292382659002826b98029517f8308276880233070233083309645a3300720a6401821770c86707821c6033020010532700f01ec82c088287c97809ab5911c9670901828aab7aef7b89330b019516f83081675402816858029519a0207a9750821720be87077a6774027a97549517f0207b6778024926800208951770337b6748018217187b67500195174c337b6758018217107b67600195186c337b6868017b6770018217087b670801492610010349262801951740327b671801492620010395178033951800325010745e2282659002826b98028266880233070233083309645a3300760a640133020010821c60821770c86707532700f01cc82c088287c97809ab590fc9670901828aab7aef7b89019516f830826758028268ab87198217587a674802951844339515a0208157587a8728169589ff951848339515a020ab97098157587a87018328089517f0200a137b6778020a7b57403307780b017b670801951850337b6848018217687b6750017b6858017b676001951870337b6868017b6770019518e0207b6878017b678001951740337b6788018217487b679001492610010549262801951840327b68180149262001059517803395180032501078682182659002826b98029517f8308276880233070233083309645a33007a0a640133020010821770c86707821c60532700f06cfdc82c088287c97809ab595efdc9670901828aab7aee7b89330b01ab7ae62849fd9517443395184833951940337b6948018219487b6950017b6758017b6960017b6868017b6970013307980a017b670801492610010349262801951840327b6818014926200103951780339518003250107cc32082659002826b98029517f8308276880233070233083309645a33007e0a6401821770c86707532700f02182186095870010018278c98709ab590fc9680901827aab8af27b79019515a0208257480a1a9516f8307b6778020a7b57409517e8207b674801951770337b6758019517e0207b6768018217687b6750017b6760017b6770013307c80a017b670801951740327b6718014926100103492620010349262801951780339518003250208000152082659002826b98028266880233070233083309645a330082000a6401821770c86707532700f02c82186095870010018278c98709ab591ac9680901827aab8af27b79330b951a403333080c2823f1951a403333080c2819f100951108f87b10f0077b15e8077b16e0079511c0fb330908ac980a0152070628c31c95790452090628bb1c7c79047b19407c79057b19287c79067b19387c79077b1930958af8957508510a457d583306015908408489ff003306025329c0002d3306035329e000253306045329f0001d3306055329f800153306065329fc000d8898fe009a860801ae6a092897003306017b16486457646864a650208400db2b821a4851077fe4a607c9a70753176076c85a089576a09587607b174851064f7d783305015908378489ff003305025329c0002d3305035329e000253305045329f0001d3305055329f800153305065329fc000d8898fe009a850801ae560628e61b645850208600722b28073305330701e45608c95808e47808c97808330921ae982333083305000001016457951140048210f0078215e8078216e0079511f8073200821948c89505c857077c792051090a3306330a288600958adf957521510a577d573306015907378477ff003306025327c0002d3306035327e000253306045327f0001d3306055327f800153306065327fc000d8877fe009a7608017b1a48ae6a0628431b6457646850208800cb2a821a4828073306330701e46a08c96808e6780ac85606521a241580682064670a0e330833050000012852ff821728977708821840d48707821838978810821930979918d49808d487077b173846115181659517513308017b161864697b1a200a034611526a461153614611546d461155444611564f461157544611586a4611590d46115a4a46115b1946115cd10046115d990046115e5046115f5746116013461161fc0046116265461163f50046116431461165034611668e0046116773330bf100781b68461169d80046116a850046116b6446116c5646116d3246116ec80046116fae0046117050330c3c781c714611724f4611730c4611744d4611755e46117619461177a700461178bf00461179a90046117abb0046117b0f46117ca40046117d960046117e870046117f4746218000e600462181003d781c8200781b830046218400e7009516ff0795669903462185004a462186004946218700dd0046218800c40046218900a60046218a00ec0046218b00a80046218c009a0046218d006a46218e006f46218f0033462190009d0046219100a3004621920033462193007f46219400d20046219500eb0046219600554621970007491148ffef9517980033090001330850208a00671f7b15289557ff330548000133091a7b194054170907288f179777023308000001c887078177c887077b15303207951852330903951a9800330c0001821738330b0a027b677033075000017b17107b67188218407b68209517ff07957709047b67287b68303307c80b017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150208e00a71b826550826b589517ff079577990382764833070233083309645a330090000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677033080150209200a528951752330803951955330a030a037b67788217107b67189517ff07957711047b67283307f80b017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b67309517ff079577e1039518980150209400e91a826550826b5882664833070233083309645a330096000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677833080233050250209800ec27951852330903951a9800330c0001821738330b0a027b6780008217307b67188218407b68209517ff07957719047b67287b68303307280c017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0019517ff079577e1039518980150209a00291a826550826b5882664833070233083309645a33009c000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267800033080550209e002e2795175233080a0f7b6733076000017b67183307580c017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e103951898015020a0008019826550826b5882664833070233083309645a3300a2000a6401821748c86707532700f0db09330740000395770010018278c98709ab59c609c9680901827aab8af17b79330b01ab8ae928b109951852330903951a9800330c0001821738330b0a027b67789517ff07957711047b67283307880c017b1798017b65188218407b68207b68304921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020a600d018826550826b589517ff079577990382764833070233083309645a3300a8000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308013305015020aa00cb259517523308033309330a0a037b6780009517ff07957719047b67483307b80c017b1798014921a001024921b8019517ff079577e1037b17a8017b15b0018217407b67509517ff079577b103951898015020ac001a18826520826b2882661833070233083309645a3300ae000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308023305025020b0001c25951852330903951a9800330c0001821738330b0a027b6733075000017b67183307d80c017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0018217407b67207b66287b67309517ff079577e103951898015020b2006117826550826b5882664833070233083309645a3300b4000a6401821748c86707532700f02402330740000395770010018278c98709ab590f02c9680901827aab8af17b79330b01ab8ae928fa019517583308030a0e7b67789517ff07957711047b67283307080d017b1798017b65188218407b68207b68304921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020b800be16826550826b589517ff079577990382764833070233083309645a3300ba000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308013305015020bc00b9239517583308030a0d7b6780009517ff07957719047b67483307380d017b1798014921a001024921b8019517ff079577e1037b17a8017b15b0018217407b67509517ff079577b103951898015020be000c16826520826b2882661833070233083309645a3300c0000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308023305025020c2000e239517783308030a0d7b6733075000017b67183307580d017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0018217407b67207b66287b67309517ff079577e103951898015020c4006015826550826b5882664833070233083309645a3300c6000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267330805330056012863229517583308030a0f7b67709517ff07957709047b67283307880d017b1798017b65188218407b68207b68304921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020ca00b314826550826b589517ff079577990382764833070233083309645a3300cc000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267703308013305015020ce00ae219517583308030a0d7b67789517ff07957711047b67483307b80d017b1798014921a001024921b8019517ff079577e1037b17a8017b15b0018217407b67509517ff079577b103951898015020d0000214826520826b2882661833070233083309645a3300d2000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308023305025020d400052195187895199800330b03821738330a0a017b67800033075000017b67189517ff07957719047b67283307d80d017b1798014921a001034921b8019517ff079577b1037b17a8018217407b67207b67307b15b0019517ff079577e103951898015020d6004413826550826b5882664833070233083309645a3300d8000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308055020da0049203307e8039518520a067b6733073800017b67183307080e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e103951898015020dc009912826550826b5882664833070233083309645a3300de000a6401821748c86707532700f0f402330740000395770010018278c98709ab59df02c9680901827aab8af17b79330b01ab8ae928ca0295185895199800330b03821738330a0a017b67707b65188218407b68209517ff07957709047b67287b68303307380e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020e200ed11826550826b589517ff079577990382764833070233083309645a3300e4000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267703308015020e600eb1e9517583308030a0d7b67789517ff07957711047b67283307680e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b67309517ff079577e103951898015020e8003511826550826b5882664833070233083309645a3300ea000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308023305025020ec00381e9518588217380a0c7b67800033073000017b17107b67188218407b68209517ff07957719047b67287b68303307980e017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0019517ff079577e103951898015020ee007d10826550826b5882664833070233083309645a3300f0000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308055020f200821d1407ffffffffffff0000951a5833083309330b0a057b678217107b67183307c80e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e103951898015020f400c80f826550826b5882664833070233083309645a3300f6000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382673308063300560128cb1c9517583308030a0e7b67703308015020fa00ba1c7b65188218407b68209517ff07957709047b67287b68303307f80e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020fc00120f826550826b589517ff079577990382764833070233083309645a3300fe000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019517583308030a0d9518ff07958899037b87789517ff07957711047b87283307680e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b87188217407b87207b87309517ff079577e103951898019515980150200001620e9517ff0795779903827650827b588277487b171033070233083309646a330002010a6401821c10821748c8c707532700f023330740000395770010018278c98709ab690fc9c80901827aab8af27b79019517ff0795779903827778330802502004015a1b3309000a9517980133085020060115113306500195185833092064575020080151109566ff9555205206ec9518980133070a069516ff07956699037b6780009517ff07957719047b67583307280f017b6718491620039517ff079577e1037b6728491630028217307b67488217407b67507b67604916389517ff07957799039518ff079588b10350200a01710d826508826b10826633070233083309645a33000c010a6401821748c86707532700f01205330740000395770010018278c98709ab59fd04c9680901827aab8af17b79330b01ab8ae928e8049517583308030a0f7b6780007b65188218407b68209517ff07957719047b67287b68303307880d017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150201001ce0c826550826b589517ff079577990382764833070233083309645a330012010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267800033080150201401cb199517583308030a0d7b673307580f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b66287b67309517ff079577e10395189801502016011e0c826550826b5882664833070233083309645a330018010a6401821748c86707532700f08001330740000395770010018278c98709ab596b01c9680901827aab8af17b79330b01ab8ae928560195185895199800330b03821738330a0a017b6780007b65188218407b68209517ff07957719047b67287b68303307880f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150201c01710b826550826b589517ff079577990382764833070233083309645a33001e010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382678000330801502020016e189517583308030a0d7b673307b80f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b66287b67309517ff079577e1039518980150202201c10a826550826b5882664833070233083309645a330024010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382673308023300560128c41795175833080333098f03330a8f030a097b67707b65188218407b68209517ff07957709047b67287b68303307e80f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e10395189801502028010c0a826550826b589517ff079577990382764833070233083309645a33002a010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677033080150202c010a1795175833088f0333098f030a0a7b67789517ff07957711047b672833071810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b67309517ff079577e1039518980150202e014f09826550826b5882664833070233083309645a330030010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677833080233050250203201521648068f034816084816048f03330801330901951aff0795aa9903330b0133070a057b6780009517ff07957719047b672833074810017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0018217307b67188217407b67207b67309517ff079577e10395189801502034018308826550826b5882664833070233083309645a330036010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382678000330805330056012884159517553308033309330a0a037b676833075000017b17107b67188218407b68209517ff07957701047b67287b683033077810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150203a01c807826550826b589517ff079577990382764833070233083309645a33003c010a6401821748c8670733084000037b1808532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382676833080150203e01c014951755330803951952330a030a037b67709517ff07957709047b67283307a810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217107b67188217407b67207b67309517ff079577e10395189801502040010407826550826b5882664833070233083309645a330042010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267703308023305025020440109149517553308033309330a0a037b67789517ff07957711047b67483307d810017b1798017b15a0014921b8019517ff079577e1037b17a8014921b001018217407b67509517ff079577b10395189801502046015906826520826b2882661833070233083309645a330048010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677833080550204a016113951855330903951a9800330c0001821738330b0a027b6780009517ff07957719047b67283307f810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217107b67188217407b67207b67309517ff079577e1039518980150204c019d05826550826b5882664833070233083309645a33004e010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267800033080650205001a4129517553308033309330a0a037b678217107b671833072811017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e1039518980150205201f304826550826b5882664833070233083309645a330054010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826733080750205601fc1182153001951898008217380a047b67800033080850205801e2117b65188218407b68209517ff07957719047b67287b683033075811017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150205a013a04826550826b589517ff079577990382764833070233083309645a33005c010a6401821748c86707532700f025330740000395770010018278c98709ab5911c9680901827aab8af27b790a28040a019516ff07956699037b6733080950205e0135117b66488217407b675033078811017b1798014921a001024921b8019517ff079577e1037b17a8014921b001019517ff079577b10395189801502060019b03826520826b2882661833070233083309645a330062010a6401821748c86707532700f025330740000395770010018278c98709ab5911c9680901827aab8af27b79330b01821920821a285519217997a6209866203305190003330719000382181850206401a9053a080000031407abaaaaaaaaaaaaaaca7607ae872c821828511809180a08330a450601330702330b11330833090a640195672a330807502066015410320764570a10330ade0001330702330b10330833090a64330820284be400000000009511887b10707b15687b16600a7b17330804502068011a1064177b175033071a7b17583307a811017b1720491128024911409517507b17304911380195170895182050206a018e02821510821b1882160833070233083309645a33006c010a64019568ffef532800f025330740000395770010018278c98709ab5911c9680901827aab8af27b79330b013307000001330882107082156882166095117832009511b87b10407b15387b1630c88909ac895364758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950206e0133821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086f82a70851077282a91051099f0082a8330200103304400003c8240701827ac86a05aca5c300955b0188bc01d8b20bd4cb0b520bb300827bababe57b75330c7b1318c95407957700107b17107b180864957b1450207001c90354250010940082131882181033077b380828b10049130833070128a800330700103302400003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302400003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085464758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a186469502072017bfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206489828a086475510a3582983307958b080182bcc8c70795aaff95bb10520af5829a18510a248288088e88887a1085aa01d4a808897ae0a80852080a330733080128489777010151073e5707776453330800103302400003c8820b0182bcc87c0aacca5e95a501885601d85805d4650552054f82b6abc6e77bbac9a2089588001064352806330801017b177b18084911103308c81101641750207401780652072282171082180882197b57107b58087b5982103082152882162095113832000000008272330900f0952affefac9a2782770833094000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972b7b1a825708c8a707646950207a014f018217c876067b56103307821018821510821608951120320064577b1864a8646950207c0183fc8218825a1028c59511d87b10207b15187b16106486838833098000647aae982c82a81082a7ab781364a764a55020800109fe645a8258100182a708c8870778769588017ba81028ac008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672e7b1a82a708c8570795180c6469502082013fc8560682177b7610013307821020821518821610951128320064a76458646964a55020840173fb645a82551028c2648a3308c8110164a928aa049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200531910488d7a84aa07c8a70b510a0e647c0178c895cc01acbcfbc9a903843cf8c8cb0a580c1d8482ff0014090101010101010101ca920c017bbc95bb08acabfb84390752090a2813647a51090fc8a9090178a895aa01ac9afb3200827701289511a87b10507b15487b16407b18987904330827330aa10601532971027b330827951b3e3a090800037b1910491108f0d80033037b143300ffe0f505016472821710d6720798770b821908c09709c82906976930989932ca39099894119899108499fe07964c9cc86c0c97cc3198cc30c8a9097c967c9901c8ac0c7cc5017ccc78b9ff78b6fe78b50178bc9588fc95bbfcac20ac5417633697793098993296997b14989911969b9cc8b7079777319877309588fec8a7077c7b017c77951c19c88c0c78cb0178c764970155170a149588ff951919c889098377307897281c9777019588fec8a7077c79017c77951a19c88a0a78a90178a701951a19c88a0a9a8b2733088006018217330950208a011382105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208517c7638c94a0a7b19185a1601a0005206ad007b1a1028ac0082752082762864576468821a38821b3050208c0175013308015207be00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b3050208e012101520769821740c95705955501019555ff5105cb00826920330830821748b4900290015107eb28445216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510628825920821748821840b4900292015107ec330801016487821060821558821650951168320082164864676458821918821a38821b30502094018e003308015207d7825a186467821820821928b4a00296013308015207c18217109a777b17383306ff01821738c867075117ff45825920821748821840b4900298019566015107e52839826a18821748821820821928b4a0029a0133080152077eff330882168217107a6730821708786738286aff821610821710d87608285eff821710d876082855ff9511d87b10207b15187b1610839c330200001164a66485647aaa2c21825c2064a764987b1b087b1ab4c0029c01821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b167049116020330a03781a688296204911304911407b17507b185851060a018297285107790149112882957b19088298107b18189578ff9788039888039588017b18955508967838956618330788017b1710017b18208259510918821a588217508258f882aa18b4a0029e01520755018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49002a0015207bb009555108218209588c89566388217289577017b1728520834ff286b829718510773829510330a977804c858087b18207b190882969577ff9777049877049577017b17956608017b1a288269510917821a588217508268f882aa18b4a002a2015207588257825908951830b49002a401520748956610955510821a2895aa01821720ab75c5821908821a829708ac7a0d282d330a829708540726829797a804c88709821a58821750829882990882aa18b4a002a60151070833070128053307018210800082157882167095118800320032009511887b10707b15687b16606493330c3302330b1404fffefefefefefefe330a0a0a0a0a14000a0a0a0a0a0a0a0a8279107b194882797b19308277087b17287b18509588087b1833079106017b170833050a7b13207b14187b1010283ac889077c77ff9577f688770101821a4878a7821728827a18821730b4a002ac016452821320821418821010821c5833050a821b385207670184b7ff0052075b017b1240aec30a28f400acc3f100c9c308821650c8c6065518101daac3dd00330a01c8a6077c77aa57aa0095aa01aba8f428c700956907849af8c96a07d36a0a88aa01887b01d4ba0a7b1c58510a4433079582f001821b588219c89b0b01c8760c82ccc87b098299d30c05c84505e0c50cd309053a0a100003c84505e09509d4c909d2a90952091f957710ae72d32816c8a60b7cbbaa5b5495aa01aba7f59582f0ae72b4aa879900330ac87606c97308821c58c9c80833050a82124001c8a6097c99aa590b95aa01aba8f5282dc87a0a01c8ca0a95ac01ae3a33ff821750c87a0a7ca7ab5727ff285d821c58c8ca0a95ac01ac3ae92815ff643c017b1c584911380164256436aa32528217487c7751071d821728827a18330904821730821808b4a002ae01821240520734c92609821850c82808ab268dfe33072894fe643c82124028b949113864c664c57b1c588217487c775207be28d5330728063307010182107082156882166095117832009511d87b10207b15187b16108275107c59827b827608510933826a187b1808330891060133090464b77b1bb4a002b201821808821b510714330701821020821518821610951128320083879577f68877017857826c2064b7821020821518821610951128320c648a3308f8110164a928a0fb951170ff7b1088007b1580007b167864757c7708648b33080133060151071d7856084615090164578210880082158000821678951190003200649a825c80c7347c580984790452094551083282c82882c720828318330899060133090264a67b1b107b1c08b43002b601821c08821b10646a3308013306015207a764b764c8b4a002b8013308016476289652083782c82882c72082831833089d06013309013306017b1a7b1b107b1c08b43002ba01821c08821b10821a330801520765ff81c7340133060178163782c82082c9287b18187b19209518377b182881c8307cc93882c382c40882c01082c2187a176c7a18687819707b13387b14407b10487b12509517187b17583307f811017b176095183864b7b4a002bc01520721821860821758828a1833089b0601330902b4a002be01647633080128e9fe33080128e3fe51089b0064797c77510791005127ff0090006c7a570a09330a330828735527c0000d330a01330b80284a5527e0000e330a02330b40ff283c5527f0000e330a03330b20ff282e5527f8000e330a04330b10ff28205527fc000e330a05330b08ff2812887afe00330b04ff93ab02ff85aa0701ae8a2b3308c8b70764ab01c8b90c7ccc97880895bbffd4c808520bf28aa903cf9707c88707320032000000009511f8fe7b1000017b15f8007b16f0007b1778180f7b171095160f33050195170f330801951910330a080a037b16603307c4017b176864177b177033071a7b1778492180000249219000024921a000140820000000100000007b18a8004621b000034921b800024921c800027b15d8007b18e0004621e8000333082812017b183049113802951880007b1850491158029518607b1840491148029517189518305020c00104f2821520821b2882161833070233083309645a3300c2010a6401330700f09568ffefac7823330740000395770010018278c98709ab5911c9680901827aab8af27b79330b01821000018215f8008216f0009511080132009511d07b10287b15207b16186486828828826a20828b186475330880060133090164a7b4b002c6017b167817084611097b151033090264179518105020c801ecfc3307017c180852081b8217827828827720828a1833089e0601330901b4a002ca0182102882152082161895113032002124222549112992254992922444a9489624494a9210650a21a2499294242492246992a4902493240989962445a424292245b224494a4a42948a644992949484285308118d4892149122599224294942948a644992a4240951a610221a9124292245b224494a4a42948a644992949484285308118d48921491225992242525214a45b224494a4a42942984882649490a294a9292909442520a492924a5909442520a492924a5909442520a492924a590a42421912445444408899444424242424264929450922449222292a46a12118544a4260ab548444489442222922489882449129124254992444424229124919424499244124944444444444444224484880811212252a54908b1244b3312118990442211112222559a84c4922c8da4121121918844224244a44a93905892a55192244912224913922a49922484903421a9922411409226245521491392aaa43421a90a4935228a50248994aa11124242428a52a4d40891888844888810112249aa3449849464692491a4884844444424424484889024551a49424ab23492884444119188888848444424424484889024551a498294c8529324214989888808111142222222421249952621b1244b8d2449124002481149442244888810112222559a24c4922c8d2449124824128988888888888890c84894884844444424424484881011912a4d124ab23422922422119224492211111111118548a4229154445219894844849088881011912a4d426249961a8988224928800490902049424a22114924491251442422222212111189101121224444a44a93444849961a119124121122121189884884880811212252a59124a4244b234a22229588a48962424424222222222212212242448888489546922025b2d424222211111122444488081111a9d22424966469a48889888848448488082122828848154d426249968a249211119148922449922429898484848484c8a4a98224892449492424242424442605d524490a8b8888922495242591909090901099a48254932452852449922449494a11111111112144448810112212424484104944448410428410220811414408411004411042088210822084105190842492909292885442924424214244448888208948aa6812422cc9d2882448929244244488880849222248922a9a84104bb23422499044a42249229210212222222248922a9a84104bb2342212a40a09112222429244449024553409422c91a52649442a11099124212222444490442455340921966469449220a92222214244442411112449154d428825591a11499044a40a091122222249222248922a9a042196c85293a444244492848888101141129154d124845892a5114982a4884888101111494404495245931062499646441224151222444444924444902455340921966469448924252221922444448488089288a48a2621c4922c8d4812242522214244442411112449154d428825591a91244824152111091122229244440449524593106249964644824885840811112149222248922a9a042196c852934452491291840811112122822422a9a24908b1244b239220291109112222429224228224a9a24908b1244b23920449119224220911222222228224a9a24908b1244b23224100a92a09112222429244449024553409219664694489242541928824448888081111241149154d428825599a149188840811112149121111442449aa6892106249964624414441260549a22222222111914892242222484a154d82104b64a9495224894842848888101141129154d124845892a5119120a91021222224491211419254d12408b144969a24928a2411498810111122224822922a9a84104bb23422122415224444842449222248922a9a84104bb234a244928892242209112222424404494452459310624996462441224a4442848888902489882049aa6812422cc9d2882441242411a98848881011114992880892a48a2621c4922c8d8844922a21492292102122224444904424553409098925591a910449522212224444842449440449524593905892a5114982a44a444244444448222248922a9a84c4922c8d48822422151109112222429224228224a9a249482cc9d28848905425214244444892880892a48a2621b1244b234a90912241928824448888081111241149154d42882559da1125481222444484880892a48a2621c4922c35892484042180245148aa495085a44a7e922c414942224924419254d108219664a9a1242949924a922449a42c85920092699234492a49a208592249a25412490541529224429624494a4d11b22449526aa29454912cc95253a6242949924a922449a42c05250124d32469929452599224294949299322644992a494a82c0905494a4a925e4412624996aa2429a594149494245505a524a9282915944949922492484a12492289a4249244924822999292145296245505a54249922849ad2449922449254b52522aa5952449569224294ad292248900b224a964499d242521242141044b9224491249929294a4249144922449496a24492549499a24544892922429094992949492254992509224494224492541222549524a92248a541224c944929022492a9324992409c992a45492204949485232892421294942a29224499224490a5552299492a44a929a244524912449229192244949225392244492242991244955ca24492449529532499292104992244a52929424654a92849484244992924a4a929290d448a292a42a802080a42449214952924c494249924444924812d1144992244952a64c2949429224292549a22449a6246512495192a4894a4a92242449a2945249a932494a925492845448499254524a920a2522524a92282251254992849484a4241552491292929094c8244992a42449922409492149424249121541a942524814128544215144644a539224a947449424495222250921028810424408894824910449524523126249961a11519294a49042495282242509094912") + # #core_vm_blob = bytes.fromhex("3013001800000101000010ce000000e6000000f80000000a0100002e0100005201000068010000740100008001000092010000696e666f09000000040000000500000007000000726561640200000003000000203a3a2006000000010000007065656b7a65726f080000000b0000000a00000020202020706f6b650010000000000000626c657373406e3d656a656374406e3d657870756e676520206f75747075743d7969656c64406e3d5245464945200000a00001000000000006000000000000007a3d20733d206f5f62797465735f616464726573733d777269746520746f206a616d20406e3d20635f62797465735f6c656e6774683d206f5f62797465735f6c656e6774683d777269746520746f20444f5420406e3d20775f62797465735f6c656e6774683d3a2065787065637420332c20676f74203a2065787065637420cf822b7c657c3d20775f62797465735f616464726573733d20635f62797465735f616464726573733db8000100000000000200000000000000ba000100000000000300000000000000bd000100000000001100000000000000ee0001000000000010000000000000003e0101000000000011000000000000000e0101000000000010000000000000004f010100000000001100000000000000de0001000000000010000000000000006761735f726573756c743d0000000000e0010100000000000b000000000000006d616368696e65206e657720696e6465783d000000000000000201000000000012000000000000006665746368207365676d656e745f696e6465783d2066657463685f726573756c743d000000000000280201000000000014000000000000003c020100000000000e000000000000007a65726f206d3d2c20706167655f69643d207a65726f5f726573756c743d00007002010000000000070000000000000077020100000000000a0000000000000081020100000000000d00000000000000706f6b65206d3d206f3d207a3d20706f6b655f726573756c743d000000000000c0020100000000000700000000000000ba000100000000000300000000000000c7020100000000000300000000000000ca020100000000000300000000000000cd020100000000000d000000000000007a65726f20666f7220726573756c74206d3d0000000000003003010000000000120000000000000077020100000000000a0000000000000081020100000000000d000000000000006265666f7265206368696c645f766d5f7265676973746572733d00000000000078030100000000001a00000000000000696e766f6b652020696e766f6b655f726573756c743d206761733d0000000000a8030100000000000700000000000000af030100000000000f00000000000000be0301000000000005000000000000006f75747075745f62797465733d7c0000f8030100000000000d0000000000000005040100000000000100000000000000050401000000000001000000000000003a206368696c6420564d20696e737472756374696f6e20636f756e7465723d008800010000000000080000000000000038040100000000001f00000000000000be0301000000000005000000000000007065656b206368696c645f766d5f69643d2c207365676d656e745f6275665f706167655f616464726573733d2c206368696c645f706167655f616464726573733d20504147455f53495a453d207065656b5f726573756c743d000000000000008804010000000000110000000000000099040100000000001b00000000000000b4040100000000001500000000000000c9040100000000000b00000000000000d4040100000000000d00000000000000207365676d656e745f6275665b302e2e385d3d2c206368696c645f69643d2c207365675f696e6465783d000000000000380501000000000013000000000000004b050100000000000b0000000000000056050100000000000c000000000000006578706f727420693d2c20676f742000980501000000000009000000000000002e010100000000001000000000000000a1050100000000000600000000000000be030100000000000500000000000000900001000000000008000000000000004143435520000000f8050100000000000500000000000000f805010000000000050000000000000048000100000000000400000000000000726561642066726f6d206a616d20406e3d3a20657870656374204e4f4e452c20676f742020287265636f72646564206174206b657920312930060100000000001100000000000000410601000000000013000000000000005406010000000000140000000000000020287265636f72646564206174206b657920322900000000ce000100000000001000000000000000410601000000000013000000000000009806010000000000140000000000000020287265636f72646564206174206b657920352900000000300601000000000011000000000000001e010100000000001000000000000000e0060100000000001400000000000000666f72676574206a616d20406e3d3a20657870656374204855482c20676f742020287265636f72646564206174206b65792036290000000028070100000000000e00000000000000360701000000000012000000000000004807010000000000140000000000000072656164206a616d406e3d000000000090070100000000000b000000000000001e0101000000000010000000000000005406010000000000140000000000000077726974652064656c65746564206a616d406e3d3a206578706563742070726576206c656e20332c20676f7420000000d0070100000000001400000000000000e40701000000000019000000000000009806010000000000140000000000000090070100000000000b0000000000000041060100000000001300000000000000e0060100000000001400000000000000736f6c696369742068617368286a616d29406e3d3a20657870656374204f4b2c20676f742000000060080100000000001400000000000000740801000000000011000000000000005406010000000000140000000000000071756572792068617368286a616d29406e3d3a20657870656374207a65726f20726573756c742c20676f742000000000b8080100000000001200000000000000ca080100000000001a00000000000000980601000000000014000000000000007175657279206861736828646f7429406e3d0000000000001809010000000000120000000000000041060100000000001300000000000000e0060100000000001400000000000000666f726765742068617368286a616d29406e3d00000000006009010000000000130000000000000074080100000000001100000000000000540601000000000014000000000000003a20657870656374206e6f6e2d7a65726f2c20676f742000b8080100000000001200000000000000a8090100000000001700000000000000980601000000000014000000000000006c6f6f6b7570206861736828646f7429406e3d0000000000f009010000000000130000000000000041060100000000001300000000000000e006010000000000140000000000000061737369676e206a616d406e3d3a2065787065637420434f52452c20676f7420380a0100000000000d00000000000000450a01000000000013000000000000004807010000000000140000000000000070726f766964652068617368286a616d293a206578706563742057484f2c20676f742020287265636f72646564206174206b657920372900880a0100000000002300000000000000ab0a010000000000140000000000000070726f766964652068617368286a616d293a20657870656374204f4b2c20676f742020287265636f72646564206174206b65792038290000e00a0100000000002200000000000000020b01000000000014000000000000006c6f6f6b75702068617368286a616d29406e3d0000000000380b01000000000013000000000000001e010100000000001000000000000000540601000000000014000000000000003a206578706563742057484f2c20676f742000000000000080000100000000000800000000000000800b0100000000001200000000000000e006010000000000140000000000000078000100000000000800000000000000800b010000000000120000000000000048070100000000001400000000000000e00a0100000000002200000000000000ab0a010000000000140000000000000070726f766964652068617368286a616d293a20657870656374204855482c20676f74200000000000180c0100000000002300000000000000020b01000000000014000000000000003a2065787065637420322b325e33322a782c20676f742000b8080100000000001200000000000000600c01000000000017000000000000009806010000000000140000000000000061737369676e406e3d00000000000000a80c010000000000090000000000000074080100000000001100000000000000e00601000000000014000000000000003a3a2065787065637420332c20676f742000000000000000380b0100000000001300000000000000e80c010000000000110000000000000054060100000000001400000000000000b8080100000000001200000000000000a8090100000000001700000000000000540601000000000014000000000000006e657720406e3d3a2065787065637420736572766963655f696e6465782c20676f74200000000000600d0100000000000700000000000000670d0100000000001c00000000000000540601000000000014000000000000007570677261646520406e3d0000000000b80d0100000000000b000000000000007408010000000000110000000000000098060100000000001400000000000000626c65737320406e3d00000000000000f80d010000000000090000000000000074080100000000001100000000000000e006010000000000140000000000000077726974652064656c6574656420444f5420406e3d000000380e01000000000015000000000000004106010000000000130000000000000054060100000000001400000000000000fe0001000000000010000000000000004106010000000000130000000000000054060100000000001400000000000000380e0100000000001500000000000000e4070100000000001900000000000000e0060100000000001400000000000000726561642066726f6d20444f5420406e3d00000000000000e00e01000000000011000000000000004106010000000000130000000000000048070100000000001400000000000000380e010000000000150000000000000041060100000000001300000000000000ab0a0100000000001400000000000000696e666f406e3d00580f010000000000070000000000000074080100000000001100000000000000020b01000000000014000000000000006761733a20676f742020287265636f72646564206174206b6579203929000000900f0100000000000900000000000000990f0100000000001400000000000000636f7265766d20636865636b706f696e740000000000000098000100000000000800000000000000740801000000000011000000000000006f6e5f7472616e73666572206761733a20676f742020287265636f72646564206174206b657920342900000000000000081001000000000015000000000000001d100100000000001400000000000000d40100000000000018000000000000000800000000000000d601000000000000dc01000000000000e4010000000000005b0000000000000006020000000000001800000000000000080000000000000008020000000000000e0200000000000012020000000000002c202c0a0a5d307830303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839395374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20737563636573735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f72206f5f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220737461636b5374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f72206f5f627974657377726974655f726573756c74206b65793d2c20726573756c743d00000000f21201000000000011000000000000000313010000000000090000000000000056555555555555554b598638d6c56d348080808080808080c7610000811602c0f6540d00bb00c600ef001b014601590107021202cb02d60282038d03390444046b0486049804aa04bc04ce04e004f2040405160528053a054c055e057e05f3050b06a80629074507ea0706084308a008bb08520a6d0adf0afa0a710b8c0bf90b140cb40dd30d140edf0eff0e970fb70f6f108f10f8101311b211ca117712921200131c1334145814ab14fd147b159b1512162e16a517c8176e1891181d194019ec190f1a911ab11a461b621bd11bed1b961cb21c701ddd1d561ee11e3f1f5b1f26204220e020fc20a422fb2214235d23db23f42333249f24b824fa2470258925c92525263e267d26fb2614275327be27d7271a2883289c28d12841295a299929fd29162a592ab62acf2a0e2b7e2b972bd62b382c512c932c052d1e2d5d2dc52dde2d1e2e822e9b2ed22e2e2f472f7f2ff82f11304930b330cc300e3176318f31ce3141325a329932fa3213335333aa33c333023421347e34973438355c359e35ae35c03534364c368136fe3617375737b037c937fe376f388838c83821393a397939f039093a483ab03ac93a0b3b873ba03be13b583c713cb03c1c3d353d743de33dfc3d3b3eaf3ec83e083f6b3f843fc23fe33f4e406740ab40f1400a4152419d41fd4116427542a542be424943ec431145eb450f464546704696469d46c8467f47a647ad47c648ea49ae4a034b254b694b964bac4bd64bef4b4b4cfb4c954df84d084e4d4e684e6a4ef14e2f507b50ab50e150575171519c5105521e5270538953c953f1530b542c543a54eb54288c050000282a1c0000285342951178ff7b1080006482808834827784891052091b848820520845827733080164298210800095118800289348827a3308810095177f33035701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830827a3308810095177f33033701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a026427501004424982108000951188003200009511c07b10387b15307b16287b18088289288276827508828720829a183308881001330901b4a001088218087b181078171846111951052d33072a027b17019567017b17087b1620951710951820821950100ad74f9555ff8216085205e47c17180133080152071e821710827828827720828a183308c51001330901b4a0010c64780164878210388215308216289511403200951178ff7b108000648280883484891052091b8488205208467c77330801642982108000951188002849477c77330a810095187f3303570164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e128317c77330a810095187f3303370164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e195b7fe562780002a9aac8100641bc87b0b3309c61001330801330a026427501010f6478210800095118800320000951178ff7b108000648280883484891052092884882052085281778979859801977a2098aa209a77da9a0764298210800095118800288346817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a02642750101432478210800095118800320000951178ff7b108000648280883484891052091b84882052084580773308016429821080009511880028cc45817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a0264275010187b468210800095118800320000951178ff7b108000648280883484891052091b848820520845827733080164298210800095118800281545827a3308810095177f33035701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830827a3308810095177f33033701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a02642750101cc44582108000951188003200009511d07b10287b15207b16186485828828825a20828b186476330888100133090164a7b4b001207b157817084611097b161033050264179518103309025010226c4c9567087b1710641795181064595010245a4c9567107b171064179518106459501026484c9567187b171064179518106459501028364c9567207b17106417951810645950102a244c9567287b17106417951810645950102c124c9567307b17106417951810645950102e004c9567387b171064179518106459501030ee4b9567407b171064179518106459501032dc4b9567487b171064179518106459501034ca4b9567507b171064179518106459501036b84b9567587b171064179518106459501038a64b9567607b17106417951810645950103a944b3307017c180852081a8217827828827720828a183308c51001330901b4a0013c8210288215208216189511303200951108f87b10f0077b15e8077b16e007951128d47b1888007b178000951818319516c02049219000ffffef33075000017b8748013307127b8750013307a800017b17c0004921c800014921e000951860327b18d0004921d80001951710219518c00050103e513f826558826b6082665033070433083309645a3300400a640182189000c8680833020433070000f0ac782433084000039588000010018289c9980aab5a11c9690a01828bab9bf27b8a330c013307000001821b8800ac2b820095b5fc51057b821a80007da70480a933060159073d8477ff003306025327c0002d3306035327e000253306045327f0001d3306055327f800153306065327fc000d8877fe009a760801ae65062897157b19880095a7046468501042894be46508c96809d87908e47909c97909889920d498085108283308330700000128053308013309d82bc891018210f0078215e8078216e0079511f80732007b1780003307400001951818317b8748013307127b8750013307a800017b17c0004921c800014921e000951860327b18d0004921d80001951710219518c0005010441b3e9517c020827558827b6082765033070433083309645a3300460a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79014821b8004921b0004921a8004921a0004921980095179800330924330a033308330b330c0a120195179800330a0833082482198000aca926ff3307440001951818317b8748013307127b8750013307a800017b17c0004921c800014921e000951860327b18d0004921d80001951710219518c0005010485a3d9517c020827558827b6082765033070433083309645a33004a0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b019517c00033090020330850104c2d40951898009519c000330b002082178800330a0a11015117ff68fe7b1788003307300001951518317b5790003307127b5798003307a800019519c0207b9750491958014919709518a8317b986049196801951760329518102150104ea43c82565001825b58018255480133070433083309646a3300500a640182179000c8570753370000f02733074000039577000010018278c98709ab6911c9580901827aab8af27b79330b01821a8800531a03d3fd95a8fd531803cbfd84a7fe511706c3fd95a7f8531703bbfd7c17c2007c18c1007c19c000977710978808d48707d4970795a9f5ac799bfd7c18c5007c1ac4007c1bc30097881097aa08d4a808d4b808c97909ac897cfdc9890653160475fd9512cb00c82703c8380b7cbc037cb5027cba7cb90197cc10975508d45c0cd4c909979908d4a90c9566fcacc646fd7c19c7007c1ac6009799087c16ca007c15c900d4a9097c1ac800976610975508d46505d45a0a95bb043304c020c841067b697b6a087b62107b67187b63207b68287b6b307b6c387b665033081a7b68589517c8207b67607b68689517d0207b67707b68789517d8207b6780007b6888009517e0207b6790007b6898009517e8207b67a0007b68a8009517f0207b67b0007b68b8009517f8207b67c0007b1888007b68c8003307600101951618317b674801492650010849266801951810217b68580149266001089517a83195186032501052f23a82659800826ba0008266900033070333083309645a3300540a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b790a28040a019518c0207b874095170021951618317b679000821788007b6798003307f001017b87509517a8317b876049185801491870491868019517603295181021501056653a82655001826b58018266480133070433083309645a3300580a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515c02082573082583833090a147b574895170821951618317b67900033071a7b67980033071802017b575049155801491570491568019517a8317b5760951760329518102150105ad33982655001826b58018266480133070333083309645a33005c0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b013307340001951618317b6790003307127b6798003307a800019518c0207b8750491858014918709519a8317b896049186801951760329518102150105e4b3982655001826b58018266480133070433083309645a3300600a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019519c02082977b17788297087b17708297107b17688295188298207b186080974882962849218000ff0f9559ff0f98990c3308107b1788000a1701510717330ab41201330702330b3e330833090a6428e6007b165882178000c8670798770c821978c879097b15789557ffff0084770000ff957500000298580c821788000a1701510717330a761201330702330b3e330833090a6428a00082168000821770c8760698690c846700f014080000fefe00000000c9780898880c821788000a1701510716330a3a1201330702330b3c330833090a642861330900000182178800821868821a780a1601510716330afc1101330702330b3e330833090a642839821788008218606459821a580a1601510716330abe1101330702330b3e330833090a642814330a901101330702330b2e330833090a64019518183133074c00017b8790003307127b8798003307a800019519c0207b9750491958014919709518a8317b986049196801951760329518102150106290379517183182755001827b58018276480133070433083309645a3300640a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b0133050810951710213308330908105010665c3a951618314906951718217b670849161049161895171021330a0633087b15786459330b330c0a12017b6768025117ff7e0233071a7b17880033075002017b177033079002017b176833077000017b1760330540000395550000103307e002017b1758282795161831826b95bb017b6b95171021330a063308821978330c0a12017b6768025117ff26027b669000821788007b679800951880337b68a0007b67a8008217707b6748014926500102492668019518a8317b68580149266001029517403195186032501068653695171831827630827b388277287b17800033070433083309646a33006a0a6401821b800082179000c8b70753370000f01a8257c97508ab680fc9b708018259ab79f27b58019518c020808750808854951918317b97107b98183309010a17951918317b974802951728317b974801821788007b975001951830317b9858017b976001951860337b9868017b9770018217687b97900049299800034929b000951760327b97a0004929a80003951740319518a83150106cad3595171831827630827b388277287b17800033070433083309646a33006e0a6401821b800082179000c8b70753370000f01a8257c97508ab680fc9b708018259ab79f27b5801951b183182b91882b71082b808951a10217bba780297990c7bb98802330a00100a16951918317b970801951728317b974801821788007b975001951890337b9858017b9760019518a0337b9868017b9770018218607b9878017b978001951820327b9888017b9790018217587b97900049299800054929b000951760327b97a0004929a80005951740319518a831501070d53495171831827630827b388277287b17800033070433083309646a3300720a6401821b800082179000c8b70753370000f0defd8257c97508ab68d2fdc9b708018259ab79f17b58330a01ab79e928bdfd33073800017b67283307127b67303307a800017b674801492650010149266801951840317b68580149266001019517a831951860325010744c3482659800826ba0008266900033070433083309645a3300760a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b790195161831826918959a018267103308f0ef0fdb9a087b68183309010a177b6720951728317b674801951730317b675801951738317b67680133071a7b6750017b6760017b67700133074803017b679000951760327b67a00049269800034926a800034926b000951740319518a8315010789233826530826b3882662833070433083309645a33007a0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b019516183149165849165049164849164049163849167049167814070000ffff000000007b672814070000fefe000000007b6730826749268000492688004916687b676033075c00017b6708013307127b6710013307a800017b674801492650010149266801951820327b68580149266001019517a8319518603250107ccd3282659800826ba0008266900033070433083309645a33007e0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b0195174031951618317b67080133071e7b67100133079803017b674801492650010149266801951820327b68580149266001019517a8319518603250208000453282659800826ba0008266900033070433083309645a330082000a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b790195131831823228823930823438823040823b48823c50823658823560492390000000018237687b3298008238707b39a0008239787b34a800823a80007b30b000823288007b3bb8007b3cc0007b36c8007b35d000951518317b57d8007b58e0007b59e8007b5af0007b52f80033071a7b17783307c803017b177033064000039566000010019517c0208277489518a8310a197b1880007b570001951708217b5748018217787b575001951818327b5858017b576001951800217b5868017b5770018217707b570801492510010349252801951760327b57180149252001039517a033951820325020840011319517183182759002827b9802827788027b17880033070433083309645a330086000a6401821b880082179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b680195151831825700015107b90085770382188000858864d48707520737ff951740313309689518b0315020880014338257607b1780008257687b17608257707b1788008257787b1768951718318275800049274001492738014927300149272801492720014927180149271001492708019517603233090001330850208a0074339517c02082774895182032821960821a88000a159517c02082774895186032821968645a0a1595182032951a60328217800082198800645b951518310a642892fe33072c00017b5788023307127b5790023307a800017b5748014925500101492568019518a0337b5858014925600101951720329518603250208c00ca2f9517183182751001827b18018276080133070433083309645a33008e000a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b790a28040a019518c0207b874095170021951618317b67880233071a7b6790023307f001017b6748019517a0337b6758014926500101492660010149266801951720329518603250209000332f82651001826b18018266080133070433083309645a330092000a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b019517c020827748951518318258482550027a575402492548027b18705118ffc503330814090000fffe000000007b1968140700f0ffffff0f00007b176033071a7b17800033077000017b17583307e804017b1750491148f0ef0f3307067b17403307167b173833076805017b17303306400003956600001033076400017b17283307127b17203307a800017b171833070e7b17103307a805017b170828148219880095980195151831821770aa7935037b5858027b18880097890c9517c020827748825808821a68c8a909821a60d2a9097b596002330a00100a157b576802951708217b574801821780007b575001951820317b5858017b576001951878337b5868017b5770018218587b5878017b578001951880337b5888017b5790018217507b570801492510010549252801951860327b58180149252001059517a0339518203250209400a02d9517183182759002827b9802827788027b177833070333083309645a330096000a6401821b7882179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b6801951a183181a7540281a858029519c0207a9750821748be87077aa774027a9754951710217ba77802492a800208951790337ba748018217407ba7500195176c337ba758018217387ba7600195188c337ba868017ba770018217307ba70801492a100103492a2801951760327ba71801492a2001039517a0339518203250209800d72c9517183182759002827b9802827788027b177833070433083309645a33009a000a6401821b7882179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b6801951a183182a7580282a8ab8711821788007aa7480295186433280c9589ff95186833ab970d9517c0208177587a87018217287ba788028217207ba790028217187ba74801492a500101492a68019517a0337ba75801492a600101951720329518603250209c00282c9517183182751001827b1801827708017b177833070433083309645a33009e000a6401821b7882179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b680133080810951710210a13951818317b8778020a9518c0207b874095187033951918317b984801821780007b9750017b9858017b976001951890337b9868017b977001951800217b9878017b978001951760337b9788018217107b9790018217087b970801492910010549292801951860327b98180149292001059517a033951820325020a000592b9517183182759002827b9802827788027b177833070433083309645a3300a2000a6401821b7882179000c8b70753370000f0e1fc8267c97608ab58d5fcc9b708018269ab79f17b68330a01ab79e928c0fc9517643395186833951960337b59480133090e7b5950017b5758017b5960017b5868017b59700133070804017b570801492510010349252801951860327b58180149252001039517a033951820325020a400b42a9517183182759002827b98028276880233070333083309645a3300a6000a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515c0208257480a1a951618317b6778020a7b5740951708217b674801951790337b675801951700217b67680133071a7b6750017b6760017b67700133075804017b670801951760327b67180149261001034926200103492628019517a033951820325020a800ff2982659002826b98028266880233070433083309645a3300aa000a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b013307600001951618317b6788023307127b6790023307a800017b6748014926500101492668019518a0337b685801492660010195172032951860325020ac00742982651001826b18018266080133070433083309645a3300ae000a640182179000c8670753370000f03033074000039577000010018278c98709ab591ac9680901827aab8af27b79330b9517603333080c28abea9517603333080c28a1ea00951108f87b10f0077b15e8077b16e0079511a8fb7b18407b17389518ff079588b103491148ffffef33075000017b87183307127b872033070006017b17b0014921b801014921d0019518ff079588c9037b18c0014921c801019517a8009518b0015020b000af288215b000821bb8008216a80033070433083309645a3300b2000a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b01821840531808be02821638520606286b259567045207062862257c67047b17307c67057b17287c67067b17207c67077b17189589f89566085109457d673305015907408477ff003305025327c0002d3305035327e000253305045327f0001d3305055327f800153305065327fc000d8877fe009a750801ae59092847023305017b154064676458646564965020b400c234645982154051072b02e45607c957075317602102c895059576a09557607b174051064f7d783305015908378489ff003305025329c0002d3305035329e000253305045329f0001d3305055329f800153305065329fc000d8898fe009a850801ae560628872464585020b600553428073305330701e45608c95808e47808c97808330920ac98ad01821940c89505c857079585e09577207b17405105537d783306015908378489ff003306025329c0002d3306035329e000253306045329f0001d3306055329f800153306065329fc000d8898fe009a860801ae6506280f2464685020b800dc33ac560c284701330654054201821740c867077c78330a0151080c491140491138288200e46508c96808957501e4a807957bff5518020a3306330728557d573306015907378477ff003306025327c0002d3306035327e000253306045327f0001d3306055327f800153306065327fc000d8877fe009a7608017b1b40ae6b06288823645764685020ba005133821b4001c865057b1538e46b08c96808e678077b17400133074000019518ff079588b1037b87183307127b872033070006017b17b0014921b801014921d0019517ff079577c9037b17c0014921c801019517a8009518b0015020bc0006268215b000821bb8008216a80033070433083309645a3300be000a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b01821840521824338217388078200a0e33083307000001280a3308330700000101951158048210f0078215e8078216e0079511f80732008217289777087b17288217209777107b17208217189777187b171833074400019518ff079588b1037b87183307127b17107b872033070006017b17087b17b0014921b801014921d0019518ff079588c9037b18c0014921c801019517a8009518b0015020c0001f258215b000821bb8008216a80033070433083309645a3300c2000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b790146115782193880977b1758951757330801821a400a03821730821828d487077b1730821720821818d487077b172833073000019518ff079588b1037b87188217107b87208217087b17b0014921b801014921d0019518ff079588c9037b18c0014921c801019517a8009518b0015020c40065248215b000821bb8008216a80033070433083309645a3300c6000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b7901821730821828d487077b17304611626a461163614611646d461165444611664f461167544611686a4611690d46116a4a46116b1946116cd10046116d990046116e5046116f5746117013461171fc0046117265461173f50046117431461175034611768e0046117773330bf100781b78461179d80046117a850046117b6446117c5646117d3246117ec8003306ae0078167f4621800050330c3c781c8100462182004f462183000c462184004d462185005e462186001946218700a70046218800bf0046218900a90046218a00bb0046218b000f46218c00a40046218d00960046218e00870046218f004746219000e600462191003d781c9200781b930046219400e700462195004a462196004946219700dd0046219800c40046219900a60046219a00ec0046219b00a80046219c009a0046219d006a46219e006f46219f00334621a0009d004621a100a3004621a200334621a3007f4621a400d2004621a500eb004621a600554621a700079517a8003309000133085020c800cd2533073400019516ff079566b1037b67183307127b67209517587b672833071a7b673033071006017b17b0014921b801024921d0019518ff079588c9037b18c0014921c801029517ff079577f9039518b0015020ca004a22826550826b5882664833070433083309645a3300cc000a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b018217589577ff5417090728771c9777023308000001c8870781773207951862330903951aa800330c0001821730330b0a029515ff079555b1037b57709577018877019777017b17209517587b571833091a7b59209517ff07957721047b57287b19287b593033076806017b17b0014921b801034921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020d0006a21825650825b5882554882172033083309646a3300d2000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267703308015020d4009d2e951762330803951965330a030a039518587b68189518ff07958829047b68288218287b68207b68303308b006017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67789577018877019777017b17289517ff079577f9039518b0015020d600a620826550826b5882664882172833083309645a3300d8000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b1038257783308023306025020da00d62d951862330903951aa800330c0001821730330b0a027b5780009577fd8877019777017b17209517587b571833091a7b59209517ff07957731047b57287b19287b59303307f806017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b0015020dc00d51f825650825b5882554882172033083309646a3300de000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b103826780003308055020e000072d95176233080a0f9518587b68188218287b68207b683033086007017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b679577098877019777017b17287b66289517ff079577f9039518b0015020e200201f826550826b5882664882172833083309645a3300e4000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308063300b00128502c951862330903951aa800330c0001821730330b0a029515ff079555b1037b57789577fd8877019777017b17209517587b571833091a7b59209517ff07957729047b57287b19287b59303307a007017b17b0014921b801034921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020e8004a1e825650825b5882554882172033083309646a3300ea000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267783308015020ec007d2b9517623308033309330a0a039518587b68189518ff07958831047b68288218287b68207b683033080008017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780009577fd8877019777017b17289517ff079577f9039518b0015020ee00871d826550826b5882664882172833083309645a3300f0000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b103826780003308023305025020f200b62a951862330903951aa800330c0001821730330b0a029518587b681833081a7b68207b683033083008017b18b0014921b801034921d0019518ff079588c9037b18c0017b15c8017b679577018877019777017b17287b66289517ff079577f9039518b0015020f400c21c826550826b5882664882172833083309645a3300f6000a6401821748c8670753370000f0580233074000039577000010018278c98709ab594102c9680901827aab8af17b79330b01ab8ae9282c023306039517683308030a0e9515ff079555b1037b57788877019777017b17209517587b571833081a7b58209517ff07957729047b57287b18287b583033078808017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020fa00041c825650825b5882554882172033083309646a3300fc000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267783308015020fe0037299517683308030a0d9518587b68189518ff07958831047b68288218287b68207b68303308e808017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780008877019777017b17289517ff079577f9039518b00150200001481b826550826b5882664882172833083309645a330002010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b10382678000330802330502502004017728951788003308030a0d9518587b681833081a7b68207b683033083009017b18b0014921b801034921d0019518ff079588c9037b18c0017b15c8017b679577018877019777017b17287b66289517ff079577f9039518b001502006018f1a826550826b5882664882172833083309645a330008010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308053300b00128bf273306039517683308030a0f9515ff079555b1037b57688877019777017b17209517587b571833081a7b58209517ff07957719047b57287b18287b583033077809017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150200c01c719825650825b5882554882172033083309646a33000e010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b10382676833080150201001fa269517683308030a0d9518587b68189518ff07958821047b68288218287b68207b68303308c009017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67708e779777017b17289517ff079577f9039518b001502012010d19826550826b5882664882172833083309645a330014010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b103825770330802330602502016013d26951888009519a800330b03821730330a0a017b57789577018877019777017b17209517587b571833091a7b59209517ff07957729047b57287b19287b59303307080a017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b001502018014018825650825b5882554882172033083309646a33001a010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b10382677833080550201c0173253307e8039518620a069518587b68189518ff07958831047b68288218287b68207b68303308580a017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780009577068877019777017b17289517ff079577f9039518b00150201e018017826550826b5882664882172833083309645a330020010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b1038257800033080650202201b22433079a029518683309030a1b7b17289577048877019777017b17189517ff07957721047b574833071a7b17207b57503307c00a017b17b0014921b801024921d0019517ff079577f9037b17c0014921c801019517ff079577c9039518b00150202401c316825620825b2882551882171833083309646a330026010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b790133080782172850202801fe239518683309038217300a1b9516ff079566b1038218207b68503308180b017b18b0014921b801024921d0019518ff079588f9037b18c0014921c801017b678877019777017b17207b66489517ff079577c9039518b00150202a011716826520826b2882661882172033083309645a33002c010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79013308088217283300b001284e233306039518689519a800330b03821730330a0a017b17a8019577fd8877019777017b17209517589515ff079555b1037b571833081a7b58209517a8017b57287b18287b58303307500b017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b001502030014d15825650825b5882554882172033083309646a330032010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79018217a8013308015020340187229517683308030a0d9516ff079566b1039518587b68189518ff07958819047b68288218287b68207b68303308c009017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67688e779777017b17289517ff079577f9039518b001502036019214826550826b5882664882172833083309645a330038010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b10382576833080233060250203a01c2219518688217300a0c7b57709577048877019777017b17209517587b571833081a7b58209517ff07957721047b57287b18287b58303307980b017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b00150203c01cf13825650825b5882554882172033083309646a33003e010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267703308055020400102211407ffffffffffff0000951a6833083309330b0a059518587b68189518ff07958829047b68288218287b68207b68303308c80b017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67789577048877019777017b17289517ff079577f9039518b001502042010413826550826b5882664882172833083309645a330044010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b1038267783308065020460137209518683309038217300a1b7b6780008877019777017b17209517ff07957731047b674833071a7b17287b67503307f80b017b17b0014921b801024921d0019517ff079577f9037b17c0014921c801019517ff079577c9039518b001502048014b12826520826b2882661882172033083309645a33004a010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b1038267800033080750204c017d1f9518683309038217300a1b8218287b68503308400c017b18b0014921b801024921d0019518ff079588f9037b18c0014921c801017b679577098877019777017b17287b66489517ff079577c9039518b00150204e019b11826520826b2882661882172833083309645a330050010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308083300b00128cb1e3306039517683308030a0e9515ff079555b1037b577033080150205401af1e8257708877019777017b17209517587b571833081a7b58209517ff07957721047b57287b18287b583033078808017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150205601c710825650825b5882554882172033083309646a330058010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019517683308030a0d9519ff079599b1039518587b98189518ff07958829047b98288218287b98207b98309519ff079599b1033308780c017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b97788e779777017b17289517ff079577f9039518b0019515b00150205a010d109517ff079577b103827650827b588277487b172082172833083309646a33005c010a6401821c20821748c8c70753370000f02533074000039577000010018278c98709ab690fc9c80901827aab8af27b79019517ff079577b10382777833080250205e01321d3309000a9517b001330850206001c31233065001951868330920645750206201ff119566ff9555205206ec9518b00133070a069515ff079555b1037b5780008877019777017b17289517587b574833071a7b57509518ff07958831047b58587b57603307b80c017b5718491520034915389517ff079577f9037b5728491530029517ff079577b1039518ff079588c90350206401110f825608825b10825582172833083309646a330066010a6401821748c8570753370000f0790533074000039577000010018278c98709ab696205c9580901827aab8af17b79330b01ab8ae9284d053306039518689519a800330b03821730330a0a019515ff079555b1037b5780009577fd8877019777017b17209517587b571833081a7b58209517ff07957731047b57287b18287b58303307000d017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150206a01470e825650825b5882554882172033083309646a33006c010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267800033080150206e01791b9517683308030a0d9518587b68188218287b68207b68303308c009017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b678e779777017b17287b66289517ff079577f9039518b00150207001950d826550826b5882664882172833083309645a330072010a6401821748c8670753370000f0960133074000039577000010018278c98709ab597f01c9680901827aab8af17b79330b01ab8ae9286a013306039517683308030a0f9515ff079555b1037b5780008877019777017b17209517587b571833081a7b58209517ff07957731047b57287b18287b583033077809017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150207601d60c825650825b5882554882172033083309646a330078010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267800033080150207a01081a9517683308030a0d9518587b68188218287b68207b68303308300d017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b678e779777017b17287b66289517ff079577f9039518b00150207c01240c826550826b5882664882172833083309645a33007e010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308023300b00128541933060395176833080333098f03330a8f030a098e789515ff079555b1037b57709788017b18209517587b571833081a7b58209517ff07957721047b57287b18287b58303307880d017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150208201550b825650825b5882554882172033083309646a330084010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b10382677033080150208601881895176833088f0333098f030a0a9518587b68189518ff07958829047b68288218287b68207b68303308c80d017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67788877019777017b17289517ff079577f9039518b00150208801950a826550826b5882664882172833083309645a33008a010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b10382577833080233060250208c01c51748058f034815084815048f03330801330901951aff0795aab103330b0133070a057b5780008877019777017b17289517587b571833071a7b57209518ff07958831047b58287b57303307080e017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b00150208e01be09825650825b5882554882172833083309646a330090010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019517ff079577b103827780003308053300b00128ec163306039517653308033309330a0a039515ff079555b1037b57689577018877019777017b17209517587b571833081a7b58209517ff07957719047b57287b18287b58303307500e017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150209401ed08825650825b5882554882172033083309646a330096010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b103826768330801502098012016951765330803951962330a030a039518587b68189518ff07958821047b68288218287b68207b68303308800e017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67709577018877019777017b17289517ff079577f9039518b00150209a012908826550826b5882664882172833083309645a33009c010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b10382577033080250209e015c153306039517653308033309330a0a037b57789577fd8877019777017b17209517587b571833081a7b58209517ff07957729047b57287b18287b58303307b00e017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020a0016207825650825b5882554882172033083309646a3300a2010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267783308055020a4019514951865330903951aa800330c0001821730330b0a029518587b68189518ff07958831047b68288218287b68207b68303308f80e017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780009577018877019777017b17289517ff079577f9039518b0015020a6019606826550826b5882664882172833083309645a3300a8010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b103825780003308065020aa01c8133306039517653308033309330a0a037b579577018877019777017b17289517587b571833071a7b57207b55287b57303307280f017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020ac01da05825650825b5882554882172833083309646a3300ae010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019517ff079577b10382773308075020b0010e139518a8008217300a0464759517ff079577b1037b757833080864575020b201ed128857019777017b17289517589519ff079599b1037b971833081a7b98209517ff07957729047b97287b18307b98309515ff079555b1033307600f017b17b0014921b801034921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020b401f704825650825b5882554882172833083309646a3300b6010a6401821748c8570753370000f02733074000039577000010018278c98709ab6911c9580901827aab8af27b790a28040a019516ff079566b1037b6780003308095020b80125129517ff07957731047b67488217307b67503307b00f017b17b0014921b801024921d0019517ff079577f9037b17c0014921c801019517ff079577c9039518b0015020ba015404826520826b2882661833070433083309645a3300bc010a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b018219405519212101330519000333071900038218385020be016d068218583a090000031407abaaaaaaaaaaaaaaca7807ae9738330733511809270a08330ad00f01330703330b11330833090a6482175895772a3308073300c0012839113308075020c0013311320764570a109515ff079555b1037b578877019777017b17409517587b571833071a7b57207b55287b57303307e80f017b17b0014921b801024921d0019518ff079588c9037b18c0014921c801029517ff079577f9039518b0015020c2014803825650825b5882554882174033083309646a3300c4010a6401821748c8570753370000f03133074000039577000010018278c98709ab691bc9580901827aab8af27b79330b3307190003330820285edd33071900033308202853dd00000000009511887b10707b15687b16600a7b173308045020c6015b1064177b175033071a7b175833073810017b1720491128024911409517507b1730491138019517089518205020c801a002821510821b1882160833070433083309645a3300ca010a64019568ffffef53380000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b013307000001330882107082156882166095117832009511b87b10407b15387b1630c88909ac895364758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a1864695020cc0133821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206495647251087a82a70851077d82a9105109ab0082a833064000033303000010c8360601826ac85a07aca7d000957b0188bc01d8b30bd4cb0b520bc000826bababe57b67330c7b1218330a400003330b0000107b1ac8ba0ac97a077b17107b180864965020ce01d3035436000010980082121882181033077b280828b50049120833070128ac0033094000033307000010c8790901829ac85a08aca85f958b0188bc01d8b70bd4cb0b520b50829bababe77b98330c01ababdf283133094000033307000010c8790901829ac85a08aca82b958b0188bc01d8b70bd4cb0b520b1c829bababe77b98330c013307400013c9870833077b280828393307017b27082831646c82179577000010821218821608018278c98709ab6911c9c80901827aab8af27b79330b0182181033077b2808017b25107b2782103082152882162095113832009511b87b10407b15387b163095880151085464758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a1864695020d0016cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206489828a086475510a3582983307958b080182bcc8c70795aaff95bb10520af5829a18510a248288088e88887a1085aa01d4a808897ae0a80852080a3307330801284a977701015107405707796452330b4000033308000010c88b0b0182bcc87c0aacca5f95a501885601d85805d4650552055082b6abc6e77bba3308400013c9a80864252806330801017b177b1808491110330858100164175020d2019e0652072282171082180882197b57107b58087b598210308215288216209511383200000000827233090000f0952affffefac9a288277083309400003959900001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972b7b1a825708c8a70764695020d8014f018217c876067b56103307821018821510821608951120320064577b1864a864695020da016ffc8218825a1028c59511d87b10207b15187b16106486838833098000647aae982c82a81082a7ab781364a764a55020de0104fe645a8258100182a708c8870778769588017ba81028ac008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672e7b1a82a708c8570795180c64695020e0013fc8560682177b7610013307821020821518821610951128320064a76458646964a55020e2015ffb645a82551028c2648a330858100164a928cd049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200531910488d7a84aa07c8a70b510a0e647c0178c895cc01acbcfbc9a903843cf8c8cb0a580c1d8482ff0014090101010101010101ca920c017bbc95bb08acabfb84390752090a2813647a51090fc8a9090178a895aa01ac9afb3200827701289511a07b10587b15507b16487b19087b18987a04330927532a71028100330927951b463a080800037b1818491110f0d80033037b143305c810013300ffe0f505016474821718d6740798770b821810c08702c8420a97a230982832ca3808988c119888108488fe0796cc9cc8ca0a97aa3198aa30c858087c8c7c8801c85a0a7ca6017caa78b8ff78bcfe78b60178ba9599fc95bbfcac40ac5417633b97783098883296887b14988811968a9cc8a7079777319877309599fe330ac81001c8a7077c7a017c77951b21c89b0b78ba0178b764870155170a149599ff951821c89808837730788728219777019599fe3308c81001c887077c78017c77951a21c89a0a78a80178a701951b21c89b0b9a9c2733098810018217088218330a5020e8011382105882155082164895116032009511987b10607b15587b16507b1b1851084f807634846801330b2b3305000011db8b057b1528c8c8028468045108427b19303308510a1a64a5017d9b89bbc085bb01c8b8089555ff9599015205efc882027b1a3882787b1c20520823284181763495c2014911282d8468045208c44911307b1a3882787b1c20510824827508ae521e8466085206517c7938c9250a5a1901a4005209b1007b1a1028b00082752082762864576468821928821a30821b385020ea0176013308015207bf00826c186457821818821920821060821558821650951168320c7b12408178307b18087c79387b19827920827628481730307b1710461738017b194864976468821928821a30821b385020ec012101520769821740c97505955501019555ff5105cb00826920330830821748b49002ee015107eb28445219021298a90195a8019888017b1810280864a9491110018278207b18488276288177307b1740959501019555ff510528826920821748821840b49002f0015107ec330801016487821060821558821650951168320082154864576468821928821a30821b385020f2018e003308015207d7826a186457821818821920b4a002f4013308015207c18217109a777b17383305ff01821738c857075117ff45826920821748821840b49002f6019555015107e52839826a18821748821818821920b4a002f80133080152077eff33088217108219087a79308219787938286aff821510821710d87508285eff821710d875082855ff9511d87b10207b15187b1610839c330200001164a66485647aaa2c21825c2064a764987b1b087b1ab4c002fa01821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b167049116020330a03781a688296204911304911407b17507b185851060a018297285107790149112882957b19088298107b18189578ff9788039888039588017b189555089678389566183307e6017b1710017b18208259510918821a588217508258f882aa18b4a002fc01520755018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49002fe015207bb009555108218209588c89566388217289577017b1728520834ff286b829718510773829510330a977804c858087b18207b190882969577ff9777049877049577017b17956608017b1a288269510917821a588217508268f882aa18b4a00200025207588257825908951830b490020202520748956610955510821a2895aa01821720ab75c5821908821a829708ac7a0d282d330a829708540726829797a804c88709821a58821750829882990882aa18b4a002040251070833070128053307018210800082157882167095118800320032009511807b10787b15707b166864923300330b33051403fffefefefefefefe330a0a0a0a0a14040a0a0a0a0a0a0a0a8279107b194882797b19388277087b173033076800017b17083a071000037b17607b18589588087b18330c0a7b12207b13187b1410283b6406c889077c77ff9577f688770101821a4878a7821730827a18821738b4a0020a02645b8212208213188214106460330c0a821540520764018457ff00520758017b1b50ae020a28ef00ac02ec00c90208821658c806065518101daa02d800330a01c8a6077c77aac7a50095aa01aba8f428c200956907849af8c96a07d36a0a88aa01887b01d4ba0a510a453307958af0821bc80b0b2808821bc80b0b01c8760c82ccc87b098299d34c05c83505e0c50cd34905c83505e09509d4c909821c60d2c90952091f957710ae7ad52816c8a60b7cbbaacb5195aa01aba7f5958af0ae7ab9aa879b00330ac87606c97208c90808330c0a821b5001c8a6097c99aac90b95aa01aba8f5282dc87a0a01c80a0a95a001ae2a38ff821758c87a0a7ca7abc72cff2862821b50c80a0a95a001ac2ae9281aff6420014911400164b56426aa2b578217487c77510723821730827a183309048217388218087b1028b4a0020c02821b50821028520733c9b609821858c8b808abb68efe640633072895fe6420821b5028b4491140640564068217487c775207b928d633072806330701018210788215708216689511800032009511d87b10207b15187b16108275107c59827b827608510933826a187b1808330868000133090464b77b1bb4a0021002821808821b510714330701821020821518821610951128320083879577f68877017857826c2064b7821020821518821610951128320c648a330890100164a92899fb951170ff7b1088007b1580007b167864757c7708648b33080133060151071d7856084615090164578210880082158000821678951190003200649a825c80c7347c580984790452094551083282c82882c7208283183308c0100133090264a67b1b107b1c08b430021402821c08821b10646a3308013306015207a764b764c8b4a00216023308016476289652083782c82882c7208283183308c410013309013306017b1a7b1b107b1c08b430021802821c08821b10821a330801520765ff81c7340133060178163782c82082c9287b18187b19209518377b182881c8307cc93882c382c40882c01082c2187a176c7a18687819707b13387b14407b10487b12509517187b175833079010017b176095183864b7b4a0021a02520721821860821758828a183308c21001330902b4a0021c02647633080128e9fe33080128e3fe51089b0064797c77510791005127ff0090006c7a570a09330a330828735527c0000d330a01330b80284a5527e0000e330a02330b40ff283c5527f0000e330a03330b20ff282e5527f8000e330a04330b10ff28205527fc000e330a05330b08ff2812887afe00330b04ff93ab02ff85aa0701ae8a2b3308c8b70764ab01c8b90c7ccc97880895bbffd4c808520bf28aa903cf9707c88707320032000000009511f8fe7b1000017b15f8007b16f0007b1778180f7b171095160f33050195170f330801951910330a080a037b1660330722027b176864177b177033071a7b1778492180000249219000024921a000140820000000100000007b18a8004621b000034921b800024921c800027b15d8007b18e0004621e8000333081013017b183049113802951880007b1850491158029518607b18404911480295171895183050201e02d5f1821520821b2882161833070233083309645a330020020a640133070000f09568ffffefac782433074000039577000010018278c98709ab5911c9680901827aab8af27b79330b01821000018215f8008216f0009511080132009511d07b10287b15207b16186486828828826a20828b186475330888100133090164a7b4b00224027b167817084611097b151033092a02641795181050202602e8fc3307017c180852081b8217827828827720828a183308c51001330901b4a00228028210288215208216189511303200951178ff7b1080006482808834827784891052091b8488205208467c77330801642982108000951188002866f47c77330a810095187f3303570164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e128317c77330a810095187f3303370164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e195b7fe562780002b9aac8100641bc87b0b3309c61001330801330a02642750202c0213f582108000951188003200002124a29424a58814c99224292915c992242929095142528868922425098924493449524892499284444b92224a92942252244b922425a9489624494a921025248588469424a924a58814c99224292915c99224292909514252886844499252448a64499294948a6449929494842821294434a22449292245b224494a4a45b224494a4a42949014229a242529a428494a42520a492924a5909442520a492924a5909442520a492924a590944292928444921411111111811089102122424448922a8d24248425596a8848222591909090901099440a499224851a89882842442244888810112249aa341284b0244b23222292aa914484884488101121224492546924086149961a518888a821424422442291880811912a8d04212cc9522324242444449224222249120991242549924444221249924849922449249144444444444444448488101121224444aa341284b0244b3b12111121914844848848954682109664692495884884442212112222551a09425892a586884488442211112222551a09425892a5519224491244124d48aa24922421844413922a91240248a209495588a4094955a43421a90a4935422442241289881011912a8d04212cc952238a10459248a91a21111212124248518a941a2122222211222244844812a9d2880425591a49242922222222222211222244844812a9d2880425591a4922125144444444444422222211222244844812a9d288044a64a9494812224444880811912a8d04212cc9d248129294888888444488881022222449954682109664a9912449024800292209910811222244848848954682109664a9119108112222440411912a1a09425892a59124491248241211111111111191848430124544242222221221224244101111a9a211094ab2342212494422482489242222222222a220128922918a88284a88448810112122888848158d04212cc9d28e44442244440811114444aa6824086149961a892222a100124012212141928484109284242145221191489224a288888888884844442442448488202222a9a2890425591a119124121122121189884884880811414444524513094ab234a2444489449a482442448488202222a9a2890425591a51c4484444444444444424122122424410119154d1440225b2d42422221111112244448808222252452341084bb23452c4444444242242448410114144a48a4682109664a92122112244448808222255341284b0244b4512c98888482282902444888808114144a48a2641084bb2d4842449922449929444424242424264d254052592902429898484848484c8a4a09a2489244952120909090909914941522425499224519544424242424264920a3249922122498810111122828848154d82109664a989a442851111519224494244928444888808114144a48a2641084bb23429494a922409114912212222440411912a9a04212cc9d22489888888880821224284881091102222444222841042100441088220042122082108822008420841104210841051102292244988101111222248922a9a04212cc9529348422a89484524499224224988101111222248922a9a04212cc9d28824489292882409112222429224228224a9a24910c2922c8d48122411a948922489481222444444440449524593208425591a110952499210212222942489882049aa681284b0244b234a2489484524499224224988101111222248922a9a04212cc9d2882448aa2422494284888810491211419254d124086149964644122411a92449881011112549222248922a9a044258224b4d921491244912912444444484880892a48a2641084bb23422099292882409112222422489882049aa681284b0244b2322092225494284888828491211419254d1240861499646944892229224492292848888881011419254d1240861499646244152129124214244444849440449524593208425591a912488482a49922411494284888888882049aa681284b0244b2392205212912421424444882489882049aa681284b0244b2322412425492292244488880811112449154d8210966469122429220911222242491211419254d12408614996269124928a24494492481222222242440449524593208425591a09922292882409112222424a222248922a9a04212cc9d2882441529224492292840811111111419254d1240861499646244100a94a229224448888084992880892a48a2641084bb23422099214492292244488880811112449154d8210966469442448521222444484922411112449154d82109664694489242922099224492292848888881011419254d124086149962645241149121122444484944444041149922a9a24086149964624414441260549a222224992442421918844444490942a9a044258224b4d92482a229224492292848888881011419254d12408614996464482a42449881011112a4944044952459340084b64a949922222499244240911111121228224a9a24910c2922c8d8804494992102122225492880892a48a2641084bb234a24492445444922489481222222242440449524593208425591a91048928894892102122222449440449524593208425591a91248884242215499224220911222222228224a9a24910c2922c8d884492541149922489481222222242440449524593208425591a9104495212912421424444489244449024553409425892a5114990a44a922449449210111111222248922a9a04212cc9d2882448225249449284081111219224228224a9a24910c2922c8d880449aa9224499210111111222248922a9a04212cc9d28812442a222948928824114922428488881011419254d1240861499676442488481222444484880892a48a2641084bb2d4841012240490240a49952492a08a284992242142444488882049aa681284b0244b8524243f4996a024219124922049aa6808425892a58692a424492a49922491b2144a0248a649d224a9248942c8124912a51242495210484a9284902549925253085992242935a49454215992a5a64c495292249524499248590a4a0248a649d22429a5b2244952929252268590254992524865492848525292f44248425892a52a494a292505252549554129492a4a4a0565529224892492924492482229892491249248a6a424859425495541a95092244a522b4992244952c99294944a692549929524498a92b4244922802c492a595227494a82242488102c4992244924494a5292924412499284a4243592a4929094a449422a24494992240949929496244952521249529224498824a924412225495292944422952448928924214592542649324912922549a92441929290a46412494252928444494a9224499214aaa452282549952435498a4822499244222549929244a6244988244952224992aa9449924892a42a659224252192244994a4242949ca9424092909499224259594242521a99144254955004100494942429292a492644a124a52121149224944532449922429a532a524499224292549a224c994a44c22294a92342a294992842449a2524aa55499244a925492845448499254524a920a2522524a92282251254992849484a4241552491292929094c8244992a42449922409492149424249121541a942524814128544215144644a539224a94744942449522225092102881042440889482491044952454348084bb2d4888892a42485144a1225485292909024459492a4149122599224294945b224495292842821298828") + # + # #core_vm_child_blob = bytes.fromhex("2a020008000001010000106d61696e010000004348494c4c200000080001000000000006000000000000004348494c44204e4f524d206e3d206669625f6e5f323d20726573756c743d202861646472323d202861646472313d29206669625f6e5f313d2920726573756c743d0000000000000020000100000000000d000000000000002d0001000000000009000000000000003e0001000000000008000000000000004e000100000000000a0000000000000046000100000000000800000000000000580001000000000009000000000000004348494c442042415345206e3d000000c8000100000000000d00000000000000360001000000000008000000000000004348494c44205752495445206f75745f616464726573733df80001000000000018000000000000003600010000000000080000000000000026000000000000001800000000000000080000000000000028000000000000002e000000000000003600000000000000307830303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839394b598638d6c56d34431200002b028feb0300bc00c70073017e012a028802a00218033303060421049a04b5044c05ee051207e40708083e0868088d089408be0874099a09a109560a790b3c0c900cb10cf40c200d350d5e0d760dd00d850e1e0f7d0f8c0fd00f283502951178ff7b108000648280883484891052092884882052085281778979859801977a2098aa209a77da9a076429821080009511880028220a817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309600101330801330a026427501004d00a8210800095118800320000951178ff7b108000648280883484891052091b848820520845807733080164298210800095118800286b09817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309600101330801330a026427501008190a8210800095118800320000951178ff7b108000648280883484891052091b84882052084582773308016429821080009511880028b408827a3308810095177f33035701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830827a3308810095177f33033701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309600101330801330a02642750100c62098210800095118800320000951100ff7b10f8007b15f0007b16e800491108ffffef7b177b171033070400017b17d0003307027b17d80033071000017b177049117801492190009518d0007b188000492188000195174095187050100ebd04821648821b5082154033070433083309646a3300100a6401821708c8570753370000f02733071000039577000010018278c98709ab6911c9580901827aab8af27b79330b018218551802990048111c019518107b184033080a7b184895181c7b18503308067b18583308d800017b187049117802492190009518407b18800049218800029517d0009518705010122d048215d800821be0008216d00033070233083309645a3300140a6401821708c8670753370000f0150133071000039577000010018278c98709ab59fe00c9680901827aab8af17b79330b01ab8ae928e90097870c140800e0fefe00000000c878087b182081887a182c140900f0fefe00000000c897077b173081777a173cbe87077a171c9517107b177033070a7b177895182c7b1880003308067b1888009519207b1990007b17980095193c7b19a0007b18a8009519307b19b0007b17b80095171c7b17c0007b18c80033076800017b1740491148064911609518707b1850491158069517d0009518405010163f038215d800821be0008216d00033070233083309645a3300180a6401821708c8670753370000f02733071000039577000010018278c98709ab5911c9680901827aab8af27b79330b0181171097770c83770000fffe7a17309517307b17403307067b174895181c7b18507b175833071001017b177049117802492190009518407b18800049218800029517d00095187050101aab028215d800821be0008216d00033070233083309645a33001c0a6401821708c8670753370000f02733071000039577000010018278c98709ab5911c9680901827aab8af27b79330b0180173081181c7a78801730330800108210f8008215f0008216e8009511000132009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101e32821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206495647251087982a70851077c82a9105109aa0082a833061000033303000010c8360601826ac85a07aca7cf00957b0188bc01d8b30bd4cb0b520bbf00826bababe57b67330c7b1218330a100003330b0000107b1ac8ba0ac97a077b17107b18086496501020bb035436000010980082121882181033077b280828b50049120833070128ac0033091000033307000010c8790901829ac85a08aca85f958b0188bc01d8b70bd4cb0b520b50829bababe77b98330c01ababdf283133091000033307000010c8790901829ac85a08aca82b958b0188bc01d8b70bd4cb0b520b1c829bababe77b98330c013307100013c9870833077b280828393307017b27082831646c82179577000010821218821608018278c98709ab6911c9c80901827aab8af27b79330b0182181033077b2808017b25107b2782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a1864695010226dfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b1620828a086475510a3582893307959b080182bcc8c70795aaff95bb10520af5828a18510a248299088e99887a1085aa01d4a909897ae0a90952090a3307330901284a977701015107405707736452330b1000033309000010c89b0b0182bcc87c0aacca5995a501885601d85905d4650552054a82b6abc6e77bba3309100013c9a90964252806330901017b177b19084911106417501024290652072282171082180882197b57107b58087b598210308215288216209511383200000000827233090000f0952affffefac9a288277083309100003959900001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950102a41018217c876067b56103307821018821510821608951120320064577b1864a8646950102c7bfc8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a55010300ffe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950103234c8560682177b7610013307821020821518821610951128320064a76458646964a55010346efb645a82551028c42867049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a07b10587b15507b16487b19087b18987a04330927532a71028100330927951b463a080000037b1818491110f0d80033037b1433056201013300ffe0f505016474821718d6740798770b821810c08702c8420a97a230982832ca3808988c119888108488fe0796cc9cc8ca0a97aa3198aa30c858087c8c7c8801c85a0a7ca6017caa78b8ff78bcfe78b60178ba9599fc95bbfcac40ac5417633b97783098883296887b14988811968a9cc8a7079777319877309599fe330a620101c8a7077c7a017c77951b21c89b0b78ba0178b764870155170a149599ff951821c89808837730788728219777019599fe3308620101c887077c78017c77951a21c89a0a78a80178a701951b21c89b0b9a9c2733096001018217088218330a50103a1282105882155082164895116032009511987b10607b15587b16507b1b1851084f807634846801330b2b3305000011db8b057b1528c8c8028468045108427b19303308510a1a64a5017d9b89bbc085bb01c8b8089555ff9599015205efc882027b1a3882787b1c20520823284181763495c2014911282d8468045208c44911307b1a3882787b1c20510824827508ae521e8466085206507c7938c9250a5a1901a1005209ae007b1a1028ad0082752082762864576468821928821a30821b3850103c6d013308015207bc00826c186457821818821920821060821558821650951168320c7b12408178307b18087c79387b19827920827628481730307b1710461738017b194864976468821928821a30821b3850103e1901520767821740c97505955501019555ff5105c600826920330830821748b49001405107ec28435219021298a90195a8019888017b1810280864a9491110018278207b18488276288177307b1740959501019555ff510527826920821748821840b49001425107ed330801016487821060821558821650951168320082154864576468821928821a30821b3850104489003308015207d8826a186457821818821920b4a001463308015207c38217109a777b17383305ff01821738c857075117ff42826920821748821840b49001489555015107e62837826a18821748821818821920b4a0014a33080152078233088217108219087a79308219787938286fff821510821710d875082863ff821710d87508285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c0014c821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b175033073001017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307387b1710017b18207b19288259510917821a588217508258f882aa18b4a0014e52074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49001505207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a001525207568257825908951830b4900154520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0015651070833070128053307018210800082157882167095118800320089284952494a112992254952522a922549525212a284a410d1889224a58814c99224292915c99224292909514252886844499252448a64499294948a6449929494842821294434222228211221111121094952a54910c2922cb510499224211189100911912a4d02212c91a526092029012425499244221189484422422249444244a44a93208425596a1224499284442442244444aa3409425892a5262522224a92a492244912294b511240324d922649254914429648922895104a924220294912429624494a4d21644992a4d4905252856449969a3225494992549224492265299404904c93a4499252599224294949299342c892244929a4b2a490a4a424e9859084b0244b559294524a0a25254955a194241525a542999424492289a424912492484a22492489249229294991b224a92a94922451925a49922449924a96a4a4544a2b4992ac24495227494a82242488102c4992244924494a5292924412499284a4243592a4929094a449422a92a42449928424494a4b92242929892429499224449254929048499294242591482509493291245224496592249324912c494a2509494a2249c924924452924452929224499224852aa914a524a992a42649114924491212894a9224254926254922922449892449aa522649224992aa94499294442449122529494a923225492225912449525249495212498d2402") + # + # # t = reverse_bits_32(8) + # # tt = '{:08b}'.format(t) + # # ttt = count_leading_zeroes(t, 32) + # # print(t, tt, ttt) + # # import pdb;pdb.set_trace() + # + # # t = 15 + # # tt = '{:08b}'.format(t) + # # ttt = count_trailing_zeroes(t, 32) + # # print(t, tt, ttt) + # # import pdb;pdb.set_trace() + # + # + # bootstrap_service_account = await client.serviceData(block_hash, bootstrap_service_id) + # + # work_package.items.append(WorkItem( + # service=bootstrap_service_id, + # code_hash=bootstrap_service_account.code_hash, + # payload=blake2b_256_hash(core_vm_blob) + int(len(core_vm_blob)).to_bytes(length=4, byteorder='little'), + # refine_gas_limit=6000, + # accumulate_gas_limit=6000, + # import_segments=[], + # extrinsic=[], + # export_count=0 + # )) + + new_service = await client.subscribeServiceValue(0, bytes.fromhex("81e47a19e6b29b0a65b9591762ce5143ed30d0261e5d24a3201752506b20f15c")) + async for data in new_service: + corevm_service_id = int.from_bytes(data, byteorder='little') + #print("subscribeServiceValue UPDATE: ", corevm_service_id) + break + print(f"core_vm service id = {corevm_service_id}") + + await client.submitPreimage(corevm_service_id, core_vm_blob, block_hash) + print("corevm preimage submitted") + + new_preimage = await client.subscribeServiceRequest(block_hash, corevm_service_id, blake2b_256_hash(core_vm_blob), len(core_vm_blob)) + async for data in new_preimage: + print("subscribeServiceRequest UPDATE: ", data) + if data is not None and len(data) == 1: + break + print("corevm preimage available") + + + # CoreVM service is activated, create a new workpackage for corevm and provide corevm_child code blob + work_package = await create_bootservice_workpackage(client) + block_hash = work_package.context.anchor + extrinsic = blake2b_256_hash(core_vm_child_blob) + int(len(core_vm_child_blob)).to_bytes( + length=4, byteorder='little' + ) + work_package.items.append( + WorkItem( + service=corevm_service_id, + code_hash=blake2b_256_hash(core_vm_blob), + payload=b'', + refine_gas_limit=6000, + accumulate_gas_limit=6000, + import_segments=[], + extrinsic=[ + WorkItemExtrinsic.from_blob(extrinsic) + ], + export_count=0 + ) + ) + + await client.submitWorkPackage(0, work_package, [extrinsic]) + print("core_vm_child workpackage submitted") + + + new_preimage = await client.subscribeServiceRequest(block_hash, corevm_service_id, blake2b_256_hash(core_vm_child_blob), len(core_vm_child_blob)) + async for data in new_preimage: + print("subscribeServiceRequest UPDATE: ", data) + if data is not None and len(data) == 0: + break + print("core_vm_child preimage requested") + + + await client.submitPreimage(corevm_service_id, core_vm_child_blob, block_hash) + print("corevm preimage submitted") + + + new_preimage = await client.subscribeServiceRequest(block_hash, corevm_service_id, blake2b_256_hash(core_vm_child_blob), len(core_vm_child_blob)) + async for data in new_preimage: + print("subscribeServiceRequest UPDATE: ", data) + if data is not None and len(data) == 1: + break + print("core_vm_child preimage available") + + work_package = await create_bootservice_workpackage(client) + block_hash = work_package.context.anchor + extrinsic = blake2b_256_hash(core_vm_child_blob) + int(len(core_vm_child_blob)).to_bytes( + length=4, byteorder='little' + ) + work_package.items.append( + WorkItem( + service=corevm_service_id, + code_hash=blake2b_256_hash(core_vm_blob), + payload=bytes.fromhex("00000000010000000000000001000000"), + refine_gas_limit=5678, + accumulate_gas_limit=9876, + import_segments=[], + extrinsic=[ + WorkItemExtrinsic.from_blob(extrinsic) + ], + export_count=1 + ) + ) + + await client.submitWorkPackage(0, work_package, [extrinsic]) + print("core_vm trigger corevm child vm") + """ + + print("FIN!!!!!!!!") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/pyjamaz/transport/rpc/playbook.py b/pyjamaz/transport/rpc/playbook.py new file mode 100644 index 00000000..cebca8f0 --- /dev/null +++ b/pyjamaz/transport/rpc/playbook.py @@ -0,0 +1,174 @@ +import asyncio + +from pyjamaz.hashing import blake2b_256_hash +from pyjamaz.models.common import Authorizer, RefinementContext, WorkPackage, WorkItem, WorkItemExtrinsic +from pyjamaz.pvm.types import PVMProgram +from pyjamaz.pvm.utils import count_leading_zeroes, count_trailing_zeroes, reverse_bits_32 +from pyjamaz.transport.rpc.ws_client import WebsocketClient + + +async def create_workpackage(client): + best_block = await client.bestBlock() + block_hash = best_block[0] + block_timeslot = best_block[1] + + state_root = await client.stateRoot(block_hash) + beefy_root = await client.beefyRoot(block_hash) + + authorizer = Authorizer( + code_hash=bytes.fromhex('c16326432b5b3213dfd1609495e13c6b276cb474d679645337e5c2c09f19b53c'), + params=b'' + ) + context = RefinementContext( + anchor=block_hash, + state_root=state_root, + beefy_root=beefy_root, + lookup_anchor=block_hash, + lookup_anchor_slot=block_timeslot, + prerequisites=[] + ) + + return WorkPackage( + authorization=bytes.fromhex('3078'), + auth_code_host=0, + authorizer=authorizer, + context=context, + items=[] + ) + + + +async def main(): + async with WebsocketClient("ws://127.0.0.1:19800") as client: + + bootstrap_service_id = 0 + work_package = await create_workpackage(client) + block_hash = work_package.context.anchor + + core_vm_blob = bytes.fromhex("06636f7265766d481200180000020000a0008c00ffffa400ffffb600ffffc800ffffe000fffff800ffff0e01ffff1a01ffff2601ffff3801ffff0010000000000000fcfffffffffffffffaffffffffffffff657870756e6765200000000000000000ffffffffffffffff206f75747075743df7ffffffffffffff7a3d20733d206f5f62797465735f616464726573733d20635f62797465735f6c656e6774683d696e666f3a20657870656374204f4b20206f5f62797465735f6c656e6774683d20775f62797465735f6c656e6774683d3a2065787065637420cf822b7c657c3d3a20696e7365727420742c20676f74207969656c642c20657870656374204f4b20775f62797465735f616464726573733d20635f62797465735f616464726573733d6761735f726573756c743d6d616368696e65206e657720696e6465783d6665746368207365676d656e745f696e6465783d2066657463685f726573756c743d7a65726f206d3d2c20706167655f69643d207a65726f5f726573756c743d706f6b65206d3d206f3d207a3d20706f6b655f726573756c743d7a65726f20666f7220726573756c74206d3d6265666f7265206368696c645f766d5f7265676973746572733d696e766f6b652020696e766f6b655f726573756c743d206761733d6f75747075745f62797465733d7c3a206368696c6420564d20696e737472756374696f6e20636f756e7465723d7065656b206368696c645f766d5f69643d2c207365676d656e745f6275665f706167655f616464726573733d2c206368696c645f706167655f616464726573733d20504147455f53495a453d207065656b5f726573756c743d207365676d656e745f6275665b302e2e385d3d2c206368696c645f69643d2c207365675f696e6465783d6578706f727420693d2c20676f7420726561642066726f6d206a616d3a20657870656374204e4f4e452020287265636f72646564206174206b6579203129777269746520746f206a616d3a20657870656374204e4f4e452020287265636f72646564206174206b6579203229726561642066726f6d206a616d3a20657870656374204f4b2020287265636f72646564206174206b6579203529666f72676574206a616d3a20657870656374204855482020287265636f72646564206174206b657920362972656164206a616d3a20657870656374204f4b2077726974652064656c65746564206a616d3a206578706563742070726576206c656e20332c20676f742072656164206a616d3a20657870656374204e4f4e4520736f6c696369742068617368286a616d293a20657870656374204f4b2071756572792068617368286a616d293a20657870656374206e6f6e2d5a45524f2c20676f74207175657279206861736828646f74293a20657870656374204e4f4e4520666f726765742068617368286a616d293a20657870656374204f4b2071756572792068617368286a616d293a20657870656374206e6f6e2d7a65726f2c20676f74206c6f6f6b7570206861736828646f74293a20657870656374204e4f4e452061737369676e206a616d3a2065787065637420434f5245206c6f6f6b75702068617368286a616d293a20657870656374204f4b2071756572792068617368286a616d293a20657870656374204f4b20656a6563743a206578706563742057484f20626c6573733a206578706563742057484f20736f6c696369742068617368286a616d292c20657870656374204f4b2061737369676e3a20657870656374204f4b202028322b325e33322a78292c20676f74206c6f6f6b75702068617368286a616d292c20657870656374204f4b203a20332028322b325e33322a78292c20676f74206e65773a20657870656374204f4b202028736572766963655f696e646578292c20676f7420757067726164653a20657870656374204f4b20626c6573733a20657870656374204f4b2077726974652064656c6574656420444f543a20657870656374204e4f4e4520777269746520746f20444f543a20657870656374204e4f4e452077726974652064656c6574656420444f543a206578706563742070726576206c656e20332c20676f7420726561642066726f6d20444f543a20657870656374204e4f4e452020287265636f72646564206174206b657920372920287265636f72646564206174206b65792038296761733a20676f742020287265636f72646564206174206b6579203929636f7265766d20636865636b706f696e746f6e5f7472616e73666572206761733a20676f742020287265636f72646564206174206b6579203429005b696e666f726561647065656b7a65726f20202020706f6b652c202c0a0a5d307830303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839395374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20737563636573735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f72206f5f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220737461636b5374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f72206f5f627974657377726974655f726573756c74206b65793d2c20726573756c743d000000680001000000000002000000000000006a0001000000000003000000000000006d0001000000000011000000000000009e000100000000001000000000000000ee000100000000001100000000000000ae000100000000001000000000000000ff0001000000000011000000000000007e00010000000000100000000000000010010100000000000b000000000000001b0101000000000012000000000000002d01010000000000140000000000000041010100000000000e000000000000004f01010000000000070000000000000056010100000000000a0000000000000060010100000000000d000000000000006d0101000000000007000000000000006a00010000000000030000000000000074010100000000000300000000000000770101000000000003000000000000007a010100000000000d000000000000008701010000000000120000000000000056010100000000000a0000000000000060010100000000000d0000000000000099010100000000001a00000000000000b3010100000000000700000000000000ba010100000000000f00000000000000c9010100000000000500000000000000ce010100000000000d00000000000000db010100000000000100000000000000db01010000000000010000000000000040000100000000000800000000000000dc010100000000001f00000000000000c9010100000000000500000000000000fb0101000000000011000000000000000c020100000000001b00000000000000270201000000000015000000000000003c020100000000000b0000000000000047020100000000000d000000000000005402010000000000130000000000000067020100000000000b0000000000000072020100000000000c000000000000007e020100000000000900000000000000be00010000000000100000000000000087020100000000000600000000000000c9010100000000000500000000000000580001000000000008000000000000008d020100000000001b0000000000000087020100000000000600000000000000a8020100000000001400000000000000bc020100000000001a0000000000000087020100000000000600000000000000d6020100000000001400000000000000ea020100000000001900000000000000870201000000000006000000000000000303010000000000140000000000000017030100000000001700000000000000870201000000000006000000000000002e0301000000000014000000000000004203010000000000140000000000000087020100000000000600000000000000a802010000000000140000000000000056030100000000002a00000000000000d602010000000000140000000000000080030100000000001600000000000000870201000000000006000000000000000303010000000000140000000000000096030100000000001d0000000000000087020100000000000600000000000000a8020100000000001400000000000000b3030100000000002600000000000000d6020100000000001400000000000000d9030100000000001d000000000000008702010000000000060000000000000003030100000000001400000000000000f6030100000000001c0000000000000087020100000000000600000000000000a802010000000000140000000000000012040100000000002600000000000000d602010000000000140000000000000038040100000000001e00000000000000870201000000000006000000000000000303010000000000140000000000000056040100000000001800000000000000870201000000000006000000000000002e0301000000000014000000000000006e040100000000001c0000000000000087020100000000000600000000000000a80201000000000014000000000000008a040100000000001b0000000000000087020100000000000600000000000000d6020100000000001400000000000000a50401000000000012000000000000008702010000000000060000000000000003030100000000001400000000000000b7040100000000001200000000000000870201000000000006000000000000002e030100000000001400000000000000c9040100000000001d00000000000000ce000100000000001000000000000000a8020100000000001400000000000000e604010000000000120000000000000087020100000000000600000000000000030301000000000014000000000000008a040100000000001b00000000000000f8040100000000001100000000000000a802010000000000140000000000000009050100000000001c0000000000000025050100000000001400000000000000a80201000000000014000000000000008a040100000000001b00000000000000f8040100000000001100000000000000d602010000000000140000000000000039050100000000000f0000000000000048050100000000001600000000000000a80201000000000014000000000000005e05010000000000130000000000000087020100000000000600000000000000d602010000000000140000000000000071050100000000001100000000000000870201000000000006000000000000000303010000000000140000000000000082050100000000001f0000000000000087020100000000000600000000000000a8020100000000001400000000000000a1050100000000001a0000000000000087020100000000000600000000000000a8020100000000001400000000000000bb050100000000002a0000000000000003030100000000001400000000000000e5050100000000001b00000000000000870201000000000006000000000000002e03010000000000140000000000000082050100000000001f0000000000000087020100000000000600000000000000000601000000000014000000000000008e00010000000000100000000000000087020100000000000600000000000000140601000000000014000000000000002806010000000000090000000000000031060100000000001400000000000000560601000000000015000000000000006b06010000000000140000000000000076010000000000001800000000000000080000000000000078010000000000007e010000000000008601000000000000a80100000000000018000000000000000800000000000000aa01000000000000b001000000000000b401000000000000cb080100000000001100000000000000dc08010000000000090000000000000056555555555555554b598638d6c56d348080808080808080604e000080e502c00e440d00c500d000f90024014f01620118022302d902e4029803a303570462048904a404b604c804da04ec04fe04100522053405460558056a057c059c0524067f061d083808a908c40836095109bc0a710b8d0b240c3c0cf40c0c0dae0dca0d710e8c0e940fb30f01104f10cc10eb1022124112ed120813e31302148814a714371553152f1698163f170c193919a519c619031a631a7c1abc1a231b3c1b7a1bcc1be51b181c7c1c9d1cdd1c321d4b1d8c1deb1d041e371e8e1eaf1eef1e401f591f9a1fec1f052042209920ba20fa204a216321a321082221225f22b322cc22ff225f238023bd23172430247024cf24e824262584259d25da25ee253a265b26ea260e274e275e277027db27f32726287e289f28dd282e2947297a29db29fc293a2a8b2aa42ae12a402b612b9e2bfd2b162c562cc92ce22c212d842da52de82d482e612e9f2ef32e0c2f472faf2fc82f043059307230ac30c630123133317331b131ca31183254328e32be32d7325f33f8331835f03514364736723698369f36ca368137a837af37c838db398e3ae23a043b483b753b8b3bb53bce3b2a3cda3c743dd73de73d2c3e473e493ec63e0a4053408340b9402f4149417441dd41f641484361439e43c643df43004428aa050000288b150000286c32951178ff7b1080008089348277849a10520a168499205209527c778210800095118800289c387c77330b810095197f3302570164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe562780006a9abb8100641ac87a0a28437c77330b810095197f3302370164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe56278000289abb8100641ac87a0a01330902648733089f0601501004293982108000951188003200009511c07b10387b15307b16287b18088289288276827508828720829a183308800601330901b4a001088218087b181078171846111951052c3307027b17019567017b17087b1620951710951820821950100aa63f9555ff8216085205e47c17180133080152071e821710827828827720828a1833089e0601330901b4a0010c64780164878210388215308216289511403200951178ff7b1080008089348277849a10520a1684992052095182778210800095118800284737827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a01330902648733089f0601501010d6378210800095118800320000951178ff7b108000808934849a10520a168499205209527c7782108000951188002888367c77330b810095197f3302570164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe562780006a9abb8100641ac87a0a28437c77330b810095197f3302370164bc847b0f97773898773c88b30a330a30da320abeba0a789a9599ff95cbff5207e195c7fe56278000289abb8100641ac87a0a01330902648733089f060150101415378210800095118800320000951178ff7b108000808934849a10520a168499205209518077821080009511880028c735817b3309810095177f33025701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842817b3309810095177f33023701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a01330902648733089f060150101856368210800095118800320000951178ff7b108000808934849a10520a1684992052095182778210800095118800280835827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a01330902648733089f060150101c973582108000951188003200009511d07b10287b15207b16186485828828825a20828b186476330880060133090164a7b4b001207b157817084611097b161033050e641795181033090e501022263c9567087b171064179518106459501024143c9567107b171064179518106459501026023c9567187b171064179518106459501028f03b9567207b17106417951810645950102ade3b9567287b17106417951810645950102ccc3b9567307b17106417951810645950102eba3b9567387b171064179518106459501030a83b9567407b171064179518106459501032963b9567487b171064179518106459501034843b9567507b171064179518106459501036723b9567587b171064179518106459501038603b9567607b17106417951810645950103a4e3b3307017c180852081a8217827828827720828a1833089e0601330901b4a0013c8210288215208216189511303200951108f87b10f0077b15e8077b16e007951148d4330a000001531804df00958bfc510bd7007d7804807a33060159083d8488ff003306025328c0002d3306035328e000253306045328f0001d3306055328f800153306065328fc000d8888fe009a860801ae6b06287e0f7b1a6895770464687b1b7050103ee53b6475821770e46707c96707d85708e45707c95707887720d4870752075b48219800492190004921880049218000491178951778330924330a033308330b330c0a1201951a78330824531508399517a000330900203308501040f3319518789519a000330b0020821768330a0a11019578015518042b3308330a000001280533080164a73309b82bc891018210f0078215e8078216e0079511f80732009578fd531803d68478fe511806cf9578f8531803c87c18a2007c19a1007c1aa000978810979908d49808d4a8089579f5ac89a97c17a5007c1aa4007c1ba30097771097aa08d4a707d4b707c98909ac798bc97906531604859512ab00c82803c8370b7cbc037cb5027cba7cb90197cc10975508d45c0cd4c909979908d4a90c9566fcacc657ff7c19a700951aa0207c14a6009799087c16aa007c15a900d449047c19a800976610975508d46505d459093305ffef7b157095bb047ba47ba9087ba2107ba8187ba3207ba7287bab307bac387baa5033081a7ba8589517a8207ba7607ba8689517b0207ba7707ba8789517b8207ba780007ba888009517c0207ba790007ba898009517c8207ba7a0007ba8a8009517d0207ba7b0007ba8b8009517d8207ba7c0007b18687ba8c8003307e808019516f8307b6748014926500108492668019518f0207b685801492660010895178831951840325010422e2d82659800826ba0008266900033070233083309645a3300440a6401821770c86707330c400003532700f01e95c70010018278c98709ab590fc9680901827aab8af27b79017b1c600a9518a0207b87409517e0209516f8307b6790008217687b67980033076809017b17187b8750951788317b87604918580149187049186801951740329518f020501046a22c82655001826b58018266480133070233083309645a3300480a6401821770c86707532700f02182186095870010018278c98709ab590fc9680901827aab8af27b79019515a02082573082583833090a147b57489517e8209516f8307b67900033077809017b5750951788317b576049155801491568018217687b679800491570951740329518f02050104a152c82655001826b58018266480133070233083309645a33004c0a6401821770c86707532700f02182186095870010018278c98709ab590fc9680901827aab8af27b79019519a02082977b17488297087b17408297107b17388295188298207b1830809748829628491150ff0f9559ff0f98990c3308107b17580a1701510717330a8d0801330702330b3e330833090a6428e0007b1628821750c8670798770c821948c879097b15489557ffff0084770000ff957500000298580c8217580a1701510717330a4f0801330702330b3e330833090a64289c00821650821740c8760698690c846700f014080000fefe00000000c9780898880c8217580a1701510716330a130801330702330b3c330833090a64285f3309000001821758821838821a480a1601510716330ad50701330702330b3e330833090a6428388217588218306459821a280a1601510716330a970701330702330b3e330833090a642814330a690701330702330b2e330833090a64019516f830330508109517f02033083309081050104eb62d49069517f8207b67084916104916189517f020330a0633087b15586459330b330c0a12017b67680233082800017b18505117ff530233078809017b17483307a809017b17403307d809017b173828279516f830826b95bb017b6b9517f020330a063308821958330c0a12017b6768025117ff14027b6690008217687b679800951860337b68a0007b67a8008217487b674801492650010249266801951888317b68580149266001029517203195184032501050da299517f830827630827b3882752833070233083309646a3300520a6401821770c85707821c6033020010532700f01cc82c088287c97809ab690fc9570901828aab7aef7b89019518a0208087508088549515f8307b57107b58183309010a177b574802951708317b5748018217687b575001951810317b5858017b576001951840337b5868017b5770018217407b57900049259800034925b000951740327b57a0004925a8000395172031951888315010542729825630825b3882552833070233083309646a3300560a640133020010821c60821770c85707532700f01cc82c088287c97809ab690fc9570901828aab7aef7b89019515f8308259188257109518f0207b58780297990c7b598802330a00109518f8200a167b570801951708317b5748018217687b575001951870337b5858017b576001951880337b5868017b5770018218507b5878017b578001951800327b5888017b5790018217387b57900049259800054925b000951740327b57a0004925a8000595172031951888315010585728825630825b3882552833070233083309646a33005a0a640133020010821c60821770c85707532700f0f2fdc82c088287c97809ab69e4fdc9570901828aab7aee7b89330b01ab7ae628cffd826918959a018267103308f0ef0fdb9a087b68183309010a177b6720951708317b674801951710317b675801951718317b6768013307280a017b679000951740327b67a00049269800034926a800038217687b6750017b6760017b6770014926b000951720319518883150105c9d27826530826b389517f83082762833070233083309645a33005e0a6401821770c86707532700f02382186095870010018278c98709ab5911c9680901827aab8af27b79330b019516f83049165849165049164849164049163849167049167814070000ffff000000007b672814070000fefe000000007b6730826749268000492688004916687b6760951720317b67080133071e7b6710013307580a017b674801492650010149266801951700327b67580149266001019517883195184032501060da2682659800826ba0008266900033070233083309645a3300620a6401821770c86707821360532700f01e95370010018278c98709ab590fc9680901827aab8af27b7901951cf83082c72882c83082c93882ca4082cb4882c25082c658492c900000000182c5607bc7980082c7687bc8a00082c8707bc9a80082c9787bcab00082ca80007bcbb80082cb88007bc2c0007bc6c8009516f8307b65d0007b67d8007b68e0007b69e8007b6af0007b6bf8003307680a017b1748953700107b1740019517a020827748951888310a197b18587b6700019517e8207b6748018217687b6750019518f8317b6858017b6760019518e0207b6868017b6770018217487b670801492610010349262801951740327b67180149262001039517803395180032501064b72582659002826b98029517f8308276880233070233083309645a3300660a6401821770c86707821b40532700f01982b7c97b08ab580fc967080182b9ab79f27bb8019516f830826700015107ae00857703821858858864d48707520742ff9517203133096895189031501068bf278267607b17588267687b17288265707b15208267787b1738826780007b173049264001492638014926300149262801492620014926180149261001492608019517403233090001330850106a23289517a02082774895180032821928645a0a159517a02082774895184032821938821530645a0a1595180032951a4032821758821920645b0a6428a7fe0a9518a0207b87409517e0207b6788028217187b674801951780337b675801492650010149266001018217687b67900249266801951700329518403250106c7f2482651001826b18019517f8308276080133070233083309645a33006e0a6401821770c86707532700f02382186095870010018278c98709ab5911c9680901827aab8af27b79330b019517a0208277489516f830482650024926480282697a6754023308127b18487b19405119ffff02330814090000fffe000000007b1938140700f0ffffff0f00007b17303307f80a017b1728491120f0ef0f3307067b17183307167b17103307480b017b170828138219589598019516f830821740aa79ad027b6858027b185897890c9517a020827748826808821a38c8a909821a30d2a9097b696002330a00100a157b6768029517e8207b6748018217687b675001951800317b6858017b676001951858337b6868017b6770018218507b6878017b678001951860337b6888017b6790018217287b670801492610010549262801951840327b68180149262001059517803395180032501070292382659002826b98029517f8308276880233070233083309645a3300720a6401821770c86707821c6033020010532700f01ec82c088287c97809ab5911c9670901828aab7aef7b89330b019516f83081675402816858029519a0207a9750821720be87077a6774027a97549517f0207b6778024926800208951770337b6748018217187b67500195174c337b6758018217107b67600195186c337b6868017b6770018217087b670801492610010349262801951740327b671801492620010395178033951800325010745e2282659002826b98028266880233070233083309645a3300760a640133020010821c60821770c86707532700f01cc82c088287c97809ab590fc9670901828aab7aef7b89019516f830826758028268ab87198217587a674802951844339515a0208157587a8728169589ff951848339515a020ab97098157587a87018328089517f0200a137b6778020a7b57403307780b017b670801951850337b6848018217687b6750017b6858017b676001951870337b6868017b6770019518e0207b6878017b678001951740337b6788018217487b679001492610010549262801951840327b68180149262001059517803395180032501078682182659002826b98029517f8308276880233070233083309645a33007a0a640133020010821770c86707821c60532700f06cfdc82c088287c97809ab595efdc9670901828aab7aee7b89330b01ab7ae62849fd9517443395184833951940337b6948018219487b6950017b6758017b6960017b6868017b6970013307980a017b670801492610010349262801951840327b6818014926200103951780339518003250107cc32082659002826b98029517f8308276880233070233083309645a33007e0a6401821770c86707532700f02182186095870010018278c98709ab590fc9680901827aab8af27b79019515a0208257480a1a9516f8307b6778020a7b57409517e8207b674801951770337b6758019517e0207b6768018217687b6750017b6760017b6770013307c80a017b670801951740327b6718014926100103492620010349262801951780339518003250208000152082659002826b98028266880233070233083309645a330082000a6401821770c86707532700f02c82186095870010018278c98709ab591ac9680901827aab8af27b79330b951a403333080c2823f1951a403333080c2819f100951108f87b10f0077b15e8077b16e0079511c0fb330908ac980a0152070628c31c95790452090628bb1c7c79047b19407c79057b19287c79067b19387c79077b1930958af8957508510a457d583306015908408489ff003306025329c0002d3306035329e000253306045329f0001d3306055329f800153306065329fc000d8898fe009a860801ae6a092897003306017b16486457646864a650208400db2b821a4851077fe4a607c9a70753176076c85a089576a09587607b174851064f7d783305015908378489ff003305025329c0002d3305035329e000253305045329f0001d3305055329f800153305065329fc000d8898fe009a850801ae560628e61b645850208600722b28073305330701e45608c95808e47808c97808330921ae982333083305000001016457951140048210f0078215e8078216e0079511f8073200821948c89505c857077c792051090a3306330a288600958adf957521510a577d573306015907378477ff003306025327c0002d3306035327e000253306045327f0001d3306055327f800153306065327fc000d8877fe009a7608017b1a48ae6a0628431b6457646850208800cb2a821a4828073306330701e46a08c96808e6780ac85606521a241580682064670a0e330833050000012852ff821728977708821840d48707821838978810821930979918d49808d487077b173846115181659517513308017b161864697b1a200a034611526a461153614611546d461155444611564f461157544611586a4611590d46115a4a46115b1946115cd10046115d990046115e5046115f5746116013461161fc0046116265461163f50046116431461165034611668e0046116773330bf100781b68461169d80046116a850046116b6446116c5646116d3246116ec80046116fae0046117050330c3c781c714611724f4611730c4611744d4611755e46117619461177a700461178bf00461179a90046117abb0046117b0f46117ca40046117d960046117e870046117f4746218000e600462181003d781c8200781b830046218400e7009516ff0795669903462185004a462186004946218700dd0046218800c40046218900a60046218a00ec0046218b00a80046218c009a0046218d006a46218e006f46218f0033462190009d0046219100a3004621920033462193007f46219400d20046219500eb0046219600554621970007491148ffef9517980033090001330850208a00671f7b15289557ff330548000133091a7b194054170907288f179777023308000001c887078177c887077b15303207951852330903951a9800330c0001821738330b0a027b677033075000017b17107b67188218407b68209517ff07957709047b67287b68303307c80b017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150208e00a71b826550826b589517ff079577990382764833070233083309645a330090000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677033080150209200a528951752330803951955330a030a037b67788217107b67189517ff07957711047b67283307f80b017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b67309517ff079577e1039518980150209400e91a826550826b5882664833070233083309645a330096000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677833080233050250209800ec27951852330903951a9800330c0001821738330b0a027b6780008217307b67188218407b68209517ff07957719047b67287b68303307280c017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0019517ff079577e1039518980150209a00291a826550826b5882664833070233083309645a33009c000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267800033080550209e002e2795175233080a0f7b6733076000017b67183307580c017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e103951898015020a0008019826550826b5882664833070233083309645a3300a2000a6401821748c86707532700f0db09330740000395770010018278c98709ab59c609c9680901827aab8af17b79330b01ab8ae928b109951852330903951a9800330c0001821738330b0a027b67789517ff07957711047b67283307880c017b1798017b65188218407b68207b68304921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020a600d018826550826b589517ff079577990382764833070233083309645a3300a8000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308013305015020aa00cb259517523308033309330a0a037b6780009517ff07957719047b67483307b80c017b1798014921a001024921b8019517ff079577e1037b17a8017b15b0018217407b67509517ff079577b103951898015020ac001a18826520826b2882661833070233083309645a3300ae000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308023305025020b0001c25951852330903951a9800330c0001821738330b0a027b6733075000017b67183307d80c017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0018217407b67207b66287b67309517ff079577e103951898015020b2006117826550826b5882664833070233083309645a3300b4000a6401821748c86707532700f02402330740000395770010018278c98709ab590f02c9680901827aab8af17b79330b01ab8ae928fa019517583308030a0e7b67789517ff07957711047b67283307080d017b1798017b65188218407b68207b68304921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020b800be16826550826b589517ff079577990382764833070233083309645a3300ba000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308013305015020bc00b9239517583308030a0d7b6780009517ff07957719047b67483307380d017b1798014921a001024921b8019517ff079577e1037b17a8017b15b0018217407b67509517ff079577b103951898015020be000c16826520826b2882661833070233083309645a3300c0000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308023305025020c2000e239517783308030a0d7b6733075000017b67183307580d017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0018217407b67207b66287b67309517ff079577e103951898015020c4006015826550826b5882664833070233083309645a3300c6000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267330805330056012863229517583308030a0f7b67709517ff07957709047b67283307880d017b1798017b65188218407b68207b68304921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020ca00b314826550826b589517ff079577990382764833070233083309645a3300cc000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267703308013305015020ce00ae219517583308030a0d7b67789517ff07957711047b67483307b80d017b1798014921a001024921b8019517ff079577e1037b17a8017b15b0018217407b67509517ff079577b103951898015020d0000214826520826b2882661833070233083309645a3300d2000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308023305025020d400052195187895199800330b03821738330a0a017b67800033075000017b67189517ff07957719047b67283307d80d017b1798014921a001034921b8019517ff079577b1037b17a8018217407b67207b67307b15b0019517ff079577e103951898015020d6004413826550826b5882664833070233083309645a3300d8000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308055020da0049203307e8039518520a067b6733073800017b67183307080e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e103951898015020dc009912826550826b5882664833070233083309645a3300de000a6401821748c86707532700f0f402330740000395770010018278c98709ab59df02c9680901827aab8af17b79330b01ab8ae928ca0295185895199800330b03821738330a0a017b67707b65188218407b68209517ff07957709047b67287b68303307380e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020e200ed11826550826b589517ff079577990382764833070233083309645a3300e4000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267703308015020e600eb1e9517583308030a0d7b67789517ff07957711047b67283307680e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b67309517ff079577e103951898015020e8003511826550826b5882664833070233083309645a3300ea000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267783308023305025020ec00381e9518588217380a0c7b67800033073000017b17107b67188218407b68209517ff07957719047b67287b68303307980e017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0019517ff079577e103951898015020ee007d10826550826b5882664833070233083309645a3300f0000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826780003308055020f200821d1407ffffffffffff0000951a5833083309330b0a057b678217107b67183307c80e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e103951898015020f400c80f826550826b5882664833070233083309645a3300f6000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382673308063300560128cb1c9517583308030a0e7b67703308015020fa00ba1c7b65188218407b68209517ff07957709047b67287b68303307f80e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e103951898015020fc00120f826550826b589517ff079577990382764833070233083309645a3300fe000a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019517583308030a0d9518ff07958899037b87789517ff07957711047b87283307680e017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b87188217407b87207b87309517ff079577e103951898019515980150200001620e9517ff0795779903827650827b588277487b171033070233083309646a330002010a6401821c10821748c8c707532700f023330740000395770010018278c98709ab690fc9c80901827aab8af27b79019517ff0795779903827778330802502004015a1b3309000a9517980133085020060115113306500195185833092064575020080151109566ff9555205206ec9518980133070a069516ff07956699037b6780009517ff07957719047b67583307280f017b6718491620039517ff079577e1037b6728491630028217307b67488217407b67507b67604916389517ff07957799039518ff079588b10350200a01710d826508826b10826633070233083309645a33000c010a6401821748c86707532700f01205330740000395770010018278c98709ab59fd04c9680901827aab8af17b79330b01ab8ae928e8049517583308030a0f7b6780007b65188218407b68209517ff07957719047b67287b68303307880d017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150201001ce0c826550826b589517ff079577990382764833070233083309645a330012010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267800033080150201401cb199517583308030a0d7b673307580f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b66287b67309517ff079577e10395189801502016011e0c826550826b5882664833070233083309645a330018010a6401821748c86707532700f08001330740000395770010018278c98709ab596b01c9680901827aab8af17b79330b01ab8ae928560195185895199800330b03821738330a0a017b6780007b65188218407b68209517ff07957719047b67287b68303307880f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150201c01710b826550826b589517ff079577990382764833070233083309645a33001e010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382678000330801502020016e189517583308030a0d7b673307b80f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b66287b67309517ff079577e1039518980150202201c10a826550826b5882664833070233083309645a330024010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382673308023300560128c41795175833080333098f03330a8f030a097b67707b65188218407b68209517ff07957709047b67287b68303307e80f017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e10395189801502028010c0a826550826b589517ff079577990382764833070233083309645a33002a010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677033080150202c010a1795175833088f0333098f030a0a7b67789517ff07957711047b672833071810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217307b67188217407b67207b67309517ff079577e1039518980150202e014f09826550826b5882664833070233083309645a330030010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677833080233050250203201521648068f034816084816048f03330801330901951aff0795aa9903330b0133070a057b6780009517ff07957719047b672833074810017b1798014921a001034921b8019517ff079577b1037b17a8017b15b0018217307b67188217407b67207b67309517ff079577e10395189801502034018308826550826b5882664833070233083309645a330036010a6401821748c86707532700f023330740000395770010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382678000330805330056012884159517553308033309330a0a037b676833075000017b17107b67188218407b68209517ff07957701047b67287b683033077810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150203a01c807826550826b589517ff079577990382764833070233083309645a33003c010a6401821748c8670733084000037b1808532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382676833080150203e01c014951755330803951952330a030a037b67709517ff07957709047b67283307a810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217107b67188217407b67207b67309517ff079577e10395189801502040010407826550826b5882664833070233083309645a330042010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267703308023305025020440109149517553308033309330a0a037b67789517ff07957711047b67483307d810017b1798017b15a0014921b8019517ff079577e1037b17a8014921b001018217407b67509517ff079577b10395189801502046015906826520826b2882661833070233083309645a330048010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff079566990382677833080550204a016113951855330903951a9800330c0001821738330b0a027b6780009517ff07957719047b67283307f810017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217107b67188217407b67207b67309517ff079577e1039518980150204c019d05826550826b5882664833070233083309645a33004e010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff07956699038267800033080650205001a4129517553308033309330a0a037b678217107b671833072811017b1798014921a001034921b8019517ff079577b1037b17a8014921b001028217407b67207b66287b67309517ff079577e1039518980150205201f304826550826b5882664833070233083309645a330054010a6401821748c86707532700f02182180895870010018278c98709ab590fc9680901827aab8af27b79019516ff0795669903826733080750205601fc1182153001951898008217380a047b67800033080850205801e2117b65188218407b68209517ff07957719047b67287b683033075811017b1798014921a001034921b8019517ff079577b1037b17a8014921b001029517ff079577e1039518980150205a013a04826550826b589517ff079577990382764833070233083309645a33005c010a6401821748c86707532700f025330740000395770010018278c98709ab5911c9680901827aab8af27b790a28040a019516ff07956699037b6733080950205e0135117b66488217407b675033078811017b1798014921a001024921b8019517ff079577e1037b17a8014921b001019517ff079577b10395189801502060019b03826520826b2882661833070233083309645a330062010a6401821748c86707532700f025330740000395770010018278c98709ab5911c9680901827aab8af27b79330b01821920821a285519217997a6209866203305190003330719000382181850206401a9053a080000031407abaaaaaaaaaaaaaaca7607ae872c821828511809180a08330a450601330702330b11330833090a640195672a330807502066015410320764570a10330ade0001330702330b10330833090a64330820284be400000000009511887b10707b15687b16600a7b17330804502068011a1064177b175033071a7b17583307a811017b1720491128024911409517507b17304911380195170895182050206a018e02821510821b1882160833070233083309645a33006c010a64019568ffef532800f025330740000395770010018278c98709ab5911c9680901827aab8af27b79330b013307000001330882107082156882166095117832009511b87b10407b15387b1630c88909ac895364758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950206e0133821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086f82a70851077282a91051099f0082a8330200103304400003c8240701827ac86a05aca5c300955b0188bc01d8b20bd4cb0b520bb300827bababe57b75330c7b1318c95407957700107b17107b180864957b1450207001c90354250010940082131882181033077b380828b10049130833070128a800330700103302400003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302400003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085464758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a186469502072017bfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206489828a086475510a3582983307958b080182bcc8c70795aaff95bb10520af5829a18510a248288088e88887a1085aa01d4a808897ae0a80852080a330733080128489777010151073e5707776453330800103302400003c8820b0182bcc87c0aacca5e95a501885601d85805d4650552054f82b6abc6e77bbac9a2089588001064352806330801017b177b18084911103308c81101641750207401780652072282171082180882197b57107b58087b5982103082152882162095113832000000008272330900f0952affefac9a2782770833094000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972b7b1a825708c8a707646950207a014f018217c876067b56103307821018821510821608951120320064577b1864a8646950207c0183fc8218825a1028c59511d87b10207b15187b16106486838833098000647aae982c82a81082a7ab781364a764a55020800109fe645a8258100182a708c8870778769588017ba81028ac008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672e7b1a82a708c8570795180c6469502082013fc8560682177b7610013307821020821518821610951128320064a76458646964a55020840173fb645a82551028c2648a3308c8110164a928aa049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200531910488d7a84aa07c8a70b510a0e647c0178c895cc01acbcfbc9a903843cf8c8cb0a580c1d8482ff0014090101010101010101ca920c017bbc95bb08acabfb84390752090a2813647a51090fc8a9090178a895aa01ac9afb3200827701289511a87b10507b15487b16407b18987904330827330aa10601532971027b330827951b3e3a090800037b1910491108f0d80033037b143300ffe0f505016472821710d6720798770b821908c09709c82906976930989932ca39099894119899108499fe07964c9cc86c0c97cc3198cc30c8a9097c967c9901c8ac0c7cc5017ccc78b9ff78b6fe78b50178bc9588fc95bbfcac20ac5417633697793098993296997b14989911969b9cc8b7079777319877309588fec8a7077c7b017c77951c19c88c0c78cb0178c764970155170a149588ff951919c889098377307897281c9777019588fec8a7077c79017c77951a19c88a0a78a90178a701951a19c88a0a9a8b2733088006018217330950208a011382105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208517c7638c94a0a7b19185a1601a0005206ad007b1a1028ac0082752082762864576468821a38821b3050208c0175013308015207be00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b3050208e012101520769821740c95705955501019555ff5105cb00826920330830821748b4900290015107eb28445216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510628825920821748821840b4900292015107ec330801016487821060821558821650951168320082164864676458821918821a38821b30502094018e003308015207d7825a186467821820821928b4a00296013308015207c18217109a777b17383306ff01821738c867075117ff45825920821748821840b4900298019566015107e52839826a18821748821820821928b4a0029a0133080152077eff330882168217107a6730821708786738286aff821610821710d87608285eff821710d876082855ff9511d87b10207b15187b1610839c330200001164a66485647aaa2c21825c2064a764987b1b087b1ab4c0029c01821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b167049116020330a03781a688296204911304911407b17507b185851060a018297285107790149112882957b19088298107b18189578ff9788039888039588017b18955508967838956618330788017b1710017b18208259510918821a588217508258f882aa18b4a0029e01520755018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49002a0015207bb009555108218209588c89566388217289577017b1728520834ff286b829718510773829510330a977804c858087b18207b190882969577ff9777049877049577017b17956608017b1a288269510917821a588217508268f882aa18b4a002a2015207588257825908951830b49002a401520748956610955510821a2895aa01821720ab75c5821908821a829708ac7a0d282d330a829708540726829797a804c88709821a58821750829882990882aa18b4a002a60151070833070128053307018210800082157882167095118800320032009511887b10707b15687b16606493330c3302330b1404fffefefefefefefe330a0a0a0a0a14000a0a0a0a0a0a0a0a8279107b194882797b19308277087b17287b18509588087b1833079106017b170833050a7b13207b14187b1010283ac889077c77ff9577f688770101821a4878a7821728827a18821730b4a002ac016452821320821418821010821c5833050a821b385207670184b7ff0052075b017b1240aec30a28f400acc3f100c9c308821650c8c6065518101daac3dd00330a01c8a6077c77aa57aa0095aa01aba8f428c700956907849af8c96a07d36a0a88aa01887b01d4ba0a7b1c58510a4433079582f001821b588219c89b0b01c8760c82ccc87b098299d30c05c84505e0c50cd309053a0a100003c84505e09509d4c909d2a90952091f957710ae72d32816c8a60b7cbbaa5b5495aa01aba7f59582f0ae72b4aa879900330ac87606c97308821c58c9c80833050a82124001c8a6097c99aa590b95aa01aba8f5282dc87a0a01c8ca0a95ac01ae3a33ff821750c87a0a7ca7ab5727ff285d821c58c8ca0a95ac01ac3ae92815ff643c017b1c584911380164256436aa32528217487c7751071d821728827a18330904821730821808b4a002ae01821240520734c92609821850c82808ab268dfe33072894fe643c82124028b949113864c664c57b1c588217487c775207be28d5330728063307010182107082156882166095117832009511d87b10207b15187b16108275107c59827b827608510933826a187b1808330891060133090464b77b1bb4a002b201821808821b510714330701821020821518821610951128320083879577f68877017857826c2064b7821020821518821610951128320c648a3308f8110164a928a0fb951170ff7b1088007b1580007b167864757c7708648b33080133060151071d7856084615090164578210880082158000821678951190003200649a825c80c7347c580984790452094551083282c82882c720828318330899060133090264a67b1b107b1c08b43002b601821c08821b10646a3308013306015207a764b764c8b4a002b8013308016476289652083782c82882c72082831833089d06013309013306017b1a7b1b107b1c08b43002ba01821c08821b10821a330801520765ff81c7340133060178163782c82082c9287b18187b19209518377b182881c8307cc93882c382c40882c01082c2187a176c7a18687819707b13387b14407b10487b12509517187b17583307f811017b176095183864b7b4a002bc01520721821860821758828a1833089b0601330902b4a002be01647633080128e9fe33080128e3fe51089b0064797c77510791005127ff0090006c7a570a09330a330828735527c0000d330a01330b80284a5527e0000e330a02330b40ff283c5527f0000e330a03330b20ff282e5527f8000e330a04330b10ff28205527fc000e330a05330b08ff2812887afe00330b04ff93ab02ff85aa0701ae8a2b3308c8b70764ab01c8b90c7ccc97880895bbffd4c808520bf28aa903cf9707c88707320032000000009511f8fe7b1000017b15f8007b16f0007b1778180f7b171095160f33050195170f330801951910330a080a037b16603307c4017b176864177b177033071a7b1778492180000249219000024921a000140820000000100000007b18a8004621b000034921b800024921c800027b15d8007b18e0004621e8000333082812017b183049113802951880007b1850491158029518607b1840491148029517189518305020c00104f2821520821b2882161833070233083309645a3300c2010a6401330700f09568ffefac7823330740000395770010018278c98709ab5911c9680901827aab8af27b79330b01821000018215f8008216f0009511080132009511d07b10287b15207b16186486828828826a20828b186475330880060133090164a7b4b002c6017b167817084611097b151033090264179518105020c801ecfc3307017c180852081b8217827828827720828a1833089e0601330901b4a002ca0182102882152082161895113032002124222549112992254992922444a9489624494a9210650a21a2499294242492246992a4902493240989962445a424292245b224494a4a42948a644992949484285308118d4892149122599224294942948a644992a4240951a610221a9124292245b224494a4a42948a644992949484285308118d48921491225992242525214a45b224494a4a42942984882649490a294a9292909442520a492924a5909442520a492924a5909442520a492924a590a42421912445444408899444424242424264929450922449222292a46a12118544a4260ab548444489442222922489882449129124254992444424229124919424499244124944444444444444224484880811212252a54908b1244b3312118990442211112222559a84c4922c8da4121121918844224244a44a93905892a55192244912224913922a49922484903421a9922411409226245521491392aaa43421a90a4935228a50248994aa11124242428a52a4d40891888844888810112249aa3449849464692491a4884844444424424484889024551a49424ab23492884444119188888848444424424484889024551a498294c8529324214989888808111142222222421249952621b1244b8d2449124002481149442244888810112222559a24c4922c8d2449124824128988888888888890c84894884844444424424484881011912a4d124ab23422922422119224492211111111118548a4229154445219894844849088881011912a4d426249961a8988224928800490902049424a22114924491251442422222212111189101121224444a44a93444849961a119124121122121189884884880811212252a59124a4244b234a22229588a48962424424222222222212212242448888489546922025b2d424222211111122444488081111a9d22424966469a48889888848448488082122828848154d426249968a249211119148922449922429898484848484c8a4a98224892449492424242424442605d524490a8b8888922495242591909090901099a48254932452852449922449494a11111111112144448810112212424484104944448410428410220811414408411004411042088210822084105190842492909292885442924424214244448888208948aa6812422cc9d2882448929244244488880849222248922a9a84104bb23422499044a42249229210212222222248922a9a84104bb2342212a40a09112222429244449024553409422c91a52649442a11099124212222444490442455340921966469449220a92222214244442411112449154d428825591a11499044a40a091122222249222248922a9a042196c85293a444244492848888101141129154d124845892a5114982a4884888101111494404495245931062499646441224151222444444924444902455340921966469448924252221922444448488089288a48a2621c4922c8d4812242522214244442411112449154d428825591a91244824152111091122229244440449524593106249964644824885840811112149222248922a9a042196c852934452491291840811112122822422a9a24908b1244b239220291109112222429224228224a9a24908b1244b23920449119224220911222222228224a9a24908b1244b23224100a92a09112222429244449024553409219664694489242541928824448888081111241149154d428825599a149188840811112149121111442449aa6892106249964624414441260549a22222222111914892242222484a154d82104b64a9495224894842848888101141129154d124845892a5119120a91021222224491211419254d12408b144969a24928a2411498810111122224822922a9a84104bb23422122415224444842449222248922a9a84104bb234a244928892242209112222424404494452459310624996462441224a4442848888902489882049aa6812422cc9d2882441242411a98848881011114992880892a48a2621c4922c8d8844922a21492292102122224444904424553409098925591a910449522212224444842449440449524593905892a5114982a44a444244444448222248922a9a84c4922c8d48822422151109112222429224228224a9a249482cc9d28848905425214244444892880892a48a2621b1244b234a90912241928824448888081111241149154d42882559da1125481222444484880892a48a2621c4922c35892484042180245148aa495085a44a7e922c414942224924419254d108219664a9a1242949924a922449a42c85920092699234492a49a208592249a25412490541529224429624494a4d11b22449526aa29454912cc95253a6242949924a922449a42c05250124d32469929452599224294949299322644992a494a82c0905494a4a925e4412624996aa2429a594149494245505a524a9282915944949922492484a12492289a4249244924822999292145296245505a54249922849ad2449922449254b52522aa5952449569224294ad292248900b224a964499d242521242141044b9224491249929294a4249144922449496a24492549499a24544892922429094992949492254992509224494224492541222549524a92248a541224c944929022492a9324992409c992a45492204949485232892421294942a29224499224490a5552299492a44a929a244524912449229192244949225392244492242991244955ca24492449529532499292104992244a52929424654a92849484244992924a4a929290d448a292a42a802080a42449214952924c494249924444924812d1144992244952a64c2949429224292549a22449a6246512495192a4894a4a92242449a2945249a932494a925492845448499254524a920a2522524a92282251254992849484a4241552491292929094c8244992a42449922409492149424249121541a942524814128544215144644a539224a947449424495222250921028810424408894824910449524523126249961a11519294a49042495282242509094912") + #core_vm_blob = bytes.fromhex("3013001800000101000010ce000000e6000000f80000000a0100002e0100005201000068010000740100008001000092010000696e666f09000000040000000500000007000000726561640200000003000000203a3a2006000000010000007065656b7a65726f080000000b0000000a00000020202020706f6b650010000000000000626c657373406e3d656a656374406e3d657870756e676520206f75747075743d7969656c64406e3d5245464945200000a00001000000000006000000000000007a3d20733d206f5f62797465735f616464726573733d777269746520746f206a616d20406e3d20635f62797465735f6c656e6774683d206f5f62797465735f6c656e6774683d777269746520746f20444f5420406e3d20775f62797465735f6c656e6774683d3a2065787065637420332c20676f74203a2065787065637420cf822b7c657c3d20775f62797465735f616464726573733d20635f62797465735f616464726573733db8000100000000000200000000000000ba000100000000000300000000000000bd000100000000001100000000000000ee0001000000000010000000000000003e0101000000000011000000000000000e0101000000000010000000000000004f010100000000001100000000000000de0001000000000010000000000000006761735f726573756c743d0000000000e0010100000000000b000000000000006d616368696e65206e657720696e6465783d000000000000000201000000000012000000000000006665746368207365676d656e745f696e6465783d2066657463685f726573756c743d000000000000280201000000000014000000000000003c020100000000000e000000000000007a65726f206d3d2c20706167655f69643d207a65726f5f726573756c743d00007002010000000000070000000000000077020100000000000a0000000000000081020100000000000d00000000000000706f6b65206d3d206f3d207a3d20706f6b655f726573756c743d000000000000c0020100000000000700000000000000ba000100000000000300000000000000c7020100000000000300000000000000ca020100000000000300000000000000cd020100000000000d000000000000007a65726f20666f7220726573756c74206d3d0000000000003003010000000000120000000000000077020100000000000a0000000000000081020100000000000d000000000000006265666f7265206368696c645f766d5f7265676973746572733d00000000000078030100000000001a00000000000000696e766f6b652020696e766f6b655f726573756c743d206761733d0000000000a8030100000000000700000000000000af030100000000000f00000000000000be0301000000000005000000000000006f75747075745f62797465733d7c0000f8030100000000000d0000000000000005040100000000000100000000000000050401000000000001000000000000003a206368696c6420564d20696e737472756374696f6e20636f756e7465723d008800010000000000080000000000000038040100000000001f00000000000000be0301000000000005000000000000007065656b206368696c645f766d5f69643d2c207365676d656e745f6275665f706167655f616464726573733d2c206368696c645f706167655f616464726573733d20504147455f53495a453d207065656b5f726573756c743d000000000000008804010000000000110000000000000099040100000000001b00000000000000b4040100000000001500000000000000c9040100000000000b00000000000000d4040100000000000d00000000000000207365676d656e745f6275665b302e2e385d3d2c206368696c645f69643d2c207365675f696e6465783d000000000000380501000000000013000000000000004b050100000000000b0000000000000056050100000000000c000000000000006578706f727420693d2c20676f742000980501000000000009000000000000002e010100000000001000000000000000a1050100000000000600000000000000be030100000000000500000000000000900001000000000008000000000000004143435520000000f8050100000000000500000000000000f805010000000000050000000000000048000100000000000400000000000000726561642066726f6d206a616d20406e3d3a20657870656374204e4f4e452c20676f742020287265636f72646564206174206b657920312930060100000000001100000000000000410601000000000013000000000000005406010000000000140000000000000020287265636f72646564206174206b657920322900000000ce000100000000001000000000000000410601000000000013000000000000009806010000000000140000000000000020287265636f72646564206174206b657920352900000000300601000000000011000000000000001e010100000000001000000000000000e0060100000000001400000000000000666f72676574206a616d20406e3d3a20657870656374204855482c20676f742020287265636f72646564206174206b65792036290000000028070100000000000e00000000000000360701000000000012000000000000004807010000000000140000000000000072656164206a616d406e3d000000000090070100000000000b000000000000001e0101000000000010000000000000005406010000000000140000000000000077726974652064656c65746564206a616d406e3d3a206578706563742070726576206c656e20332c20676f7420000000d0070100000000001400000000000000e40701000000000019000000000000009806010000000000140000000000000090070100000000000b0000000000000041060100000000001300000000000000e0060100000000001400000000000000736f6c696369742068617368286a616d29406e3d3a20657870656374204f4b2c20676f742000000060080100000000001400000000000000740801000000000011000000000000005406010000000000140000000000000071756572792068617368286a616d29406e3d3a20657870656374207a65726f20726573756c742c20676f742000000000b8080100000000001200000000000000ca080100000000001a00000000000000980601000000000014000000000000007175657279206861736828646f7429406e3d0000000000001809010000000000120000000000000041060100000000001300000000000000e0060100000000001400000000000000666f726765742068617368286a616d29406e3d00000000006009010000000000130000000000000074080100000000001100000000000000540601000000000014000000000000003a20657870656374206e6f6e2d7a65726f2c20676f742000b8080100000000001200000000000000a8090100000000001700000000000000980601000000000014000000000000006c6f6f6b7570206861736828646f7429406e3d0000000000f009010000000000130000000000000041060100000000001300000000000000e006010000000000140000000000000061737369676e206a616d406e3d3a2065787065637420434f52452c20676f7420380a0100000000000d00000000000000450a01000000000013000000000000004807010000000000140000000000000070726f766964652068617368286a616d293a206578706563742057484f2c20676f742020287265636f72646564206174206b657920372900880a0100000000002300000000000000ab0a010000000000140000000000000070726f766964652068617368286a616d293a20657870656374204f4b2c20676f742020287265636f72646564206174206b65792038290000e00a0100000000002200000000000000020b01000000000014000000000000006c6f6f6b75702068617368286a616d29406e3d0000000000380b01000000000013000000000000001e010100000000001000000000000000540601000000000014000000000000003a206578706563742057484f2c20676f742000000000000080000100000000000800000000000000800b0100000000001200000000000000e006010000000000140000000000000078000100000000000800000000000000800b010000000000120000000000000048070100000000001400000000000000e00a0100000000002200000000000000ab0a010000000000140000000000000070726f766964652068617368286a616d293a20657870656374204855482c20676f74200000000000180c0100000000002300000000000000020b01000000000014000000000000003a2065787065637420322b325e33322a782c20676f742000b8080100000000001200000000000000600c01000000000017000000000000009806010000000000140000000000000061737369676e406e3d00000000000000a80c010000000000090000000000000074080100000000001100000000000000e00601000000000014000000000000003a3a2065787065637420332c20676f742000000000000000380b0100000000001300000000000000e80c010000000000110000000000000054060100000000001400000000000000b8080100000000001200000000000000a8090100000000001700000000000000540601000000000014000000000000006e657720406e3d3a2065787065637420736572766963655f696e6465782c20676f74200000000000600d0100000000000700000000000000670d0100000000001c00000000000000540601000000000014000000000000007570677261646520406e3d0000000000b80d0100000000000b000000000000007408010000000000110000000000000098060100000000001400000000000000626c65737320406e3d00000000000000f80d010000000000090000000000000074080100000000001100000000000000e006010000000000140000000000000077726974652064656c6574656420444f5420406e3d000000380e01000000000015000000000000004106010000000000130000000000000054060100000000001400000000000000fe0001000000000010000000000000004106010000000000130000000000000054060100000000001400000000000000380e0100000000001500000000000000e4070100000000001900000000000000e0060100000000001400000000000000726561642066726f6d20444f5420406e3d00000000000000e00e01000000000011000000000000004106010000000000130000000000000048070100000000001400000000000000380e010000000000150000000000000041060100000000001300000000000000ab0a0100000000001400000000000000696e666f406e3d00580f010000000000070000000000000074080100000000001100000000000000020b01000000000014000000000000006761733a20676f742020287265636f72646564206174206b6579203929000000900f0100000000000900000000000000990f0100000000001400000000000000636f7265766d20636865636b706f696e740000000000000098000100000000000800000000000000740801000000000011000000000000006f6e5f7472616e73666572206761733a20676f742020287265636f72646564206174206b657920342900000000000000081001000000000015000000000000001d100100000000001400000000000000d40100000000000018000000000000000800000000000000d601000000000000dc01000000000000e4010000000000005b0000000000000006020000000000001800000000000000080000000000000008020000000000000e0200000000000012020000000000002c202c0a0a5d307830303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839395374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20737563636573735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a20706f6b65206661696c656420666f72206f5f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220737461636b5374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f7220775f62797465735374616e6461726450726f6772616d496e697469616c697a6174696f6e466f724368696c643a207a65726f206661696c656420666f72206f5f627974657377726974655f726573756c74206b65793d2c20726573756c743d00000000f21201000000000011000000000000000313010000000000090000000000000056555555555555554b598638d6c56d348080808080808080c7610000811602c0f6540d00bb00c600ef001b014601590107021202cb02d60282038d03390444046b0486049804aa04bc04ce04e004f2040405160528053a054c055e057e05f3050b06a80629074507ea0706084308a008bb08520a6d0adf0afa0a710b8c0bf90b140cb40dd30d140edf0eff0e970fb70f6f108f10f8101311b211ca117712921200131c1334145814ab14fd147b159b1512162e16a517c8176e1891181d194019ec190f1a911ab11a461b621bd11bed1b961cb21c701ddd1d561ee11e3f1f5b1f26204220e020fc20a422fb2214235d23db23f42333249f24b824fa2470258925c92525263e267d26fb2614275327be27d7271a2883289c28d12841295a299929fd29162a592ab62acf2a0e2b7e2b972bd62b382c512c932c052d1e2d5d2dc52dde2d1e2e822e9b2ed22e2e2f472f7f2ff82f11304930b330cc300e3176318f31ce3141325a329932fa3213335333aa33c333023421347e34973438355c359e35ae35c03534364c368136fe3617375737b037c937fe376f388838c83821393a397939f039093a483ab03ac93a0b3b873ba03be13b583c713cb03c1c3d353d743de33dfc3d3b3eaf3ec83e083f6b3f843fc23fe33f4e406740ab40f1400a4152419d41fd4116427542a542be424943ec431145eb450f464546704696469d46c8467f47a647ad47c648ea49ae4a034b254b694b964bac4bd64bef4b4b4cfb4c954df84d084e4d4e684e6a4ef14e2f507b50ab50e150575171519c5105521e5270538953c953f1530b542c543a54eb54288c050000282a1c0000285342951178ff7b1080006482808834827784891052091b848820520845827733080164298210800095118800289348827a3308810095177f33035701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830827a3308810095177f33033701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a026427501004424982108000951188003200009511c07b10387b15307b16287b18088289288276827508828720829a183308881001330901b4a001088218087b181078171846111951052d33072a027b17019567017b17087b1620951710951820821950100ad74f9555ff8216085205e47c17180133080152071e821710827828827720828a183308c51001330901b4a0010c64780164878210388215308216289511403200951178ff7b108000648280883484891052091b8488205208467c77330801642982108000951188002849477c77330a810095187f3303570164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e128317c77330a810095187f3303370164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e195b7fe562780002a9aac8100641bc87b0b3309c61001330801330a026427501010f6478210800095118800320000951178ff7b108000648280883484891052092884882052085281778979859801977a2098aa209a77da9a0764298210800095118800288346817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a02642750101432478210800095118800320000951178ff7b108000648280883484891052091b84882052084580773308016429821080009511880028cc45817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a0264275010187b468210800095118800320000951178ff7b108000648280883484891052091b848820520845827733080164298210800095118800281545827a3308810095177f33035701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830827a3308810095177f33033701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309c61001330801330a02642750101cc44582108000951188003200009511d07b10287b15207b16186485828828825a20828b186476330888100133090164a7b4b001207b157817084611097b161033050264179518103309025010226c4c9567087b1710641795181064595010245a4c9567107b171064179518106459501026484c9567187b171064179518106459501028364c9567207b17106417951810645950102a244c9567287b17106417951810645950102c124c9567307b17106417951810645950102e004c9567387b171064179518106459501030ee4b9567407b171064179518106459501032dc4b9567487b171064179518106459501034ca4b9567507b171064179518106459501036b84b9567587b171064179518106459501038a64b9567607b17106417951810645950103a944b3307017c180852081a8217827828827720828a183308c51001330901b4a0013c8210288215208216189511303200951108f87b10f0077b15e8077b16e007951128d47b1888007b178000951818319516c02049219000ffffef33075000017b8748013307127b8750013307a800017b17c0004921c800014921e000951860327b18d0004921d80001951710219518c00050103e513f826558826b6082665033070433083309645a3300400a640182189000c8680833020433070000f0ac782433084000039588000010018289c9980aab5a11c9690a01828bab9bf27b8a330c013307000001821b8800ac2b820095b5fc51057b821a80007da70480a933060159073d8477ff003306025327c0002d3306035327e000253306045327f0001d3306055327f800153306065327fc000d8877fe009a760801ae65062897157b19880095a7046468501042894be46508c96809d87908e47909c97909889920d498085108283308330700000128053308013309d82bc891018210f0078215e8078216e0079511f80732007b1780003307400001951818317b8748013307127b8750013307a800017b17c0004921c800014921e000951860327b18d0004921d80001951710219518c0005010441b3e9517c020827558827b6082765033070433083309645a3300460a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79014821b8004921b0004921a8004921a0004921980095179800330924330a033308330b330c0a120195179800330a0833082482198000aca926ff3307440001951818317b8748013307127b8750013307a800017b17c0004921c800014921e000951860327b18d0004921d80001951710219518c0005010485a3d9517c020827558827b6082765033070433083309645a33004a0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b019517c00033090020330850104c2d40951898009519c000330b002082178800330a0a11015117ff68fe7b1788003307300001951518317b5790003307127b5798003307a800019519c0207b9750491958014919709518a8317b986049196801951760329518102150104ea43c82565001825b58018255480133070433083309646a3300500a640182179000c8570753370000f02733074000039577000010018278c98709ab6911c9580901827aab8af27b79330b01821a8800531a03d3fd95a8fd531803cbfd84a7fe511706c3fd95a7f8531703bbfd7c17c2007c18c1007c19c000977710978808d48707d4970795a9f5ac799bfd7c18c5007c1ac4007c1bc30097881097aa08d4a808d4b808c97909ac897cfdc9890653160475fd9512cb00c82703c8380b7cbc037cb5027cba7cb90197cc10975508d45c0cd4c909979908d4a90c9566fcacc646fd7c19c7007c1ac6009799087c16ca007c15c900d4a9097c1ac800976610975508d46505d45a0a95bb043304c020c841067b697b6a087b62107b67187b63207b68287b6b307b6c387b665033081a7b68589517c8207b67607b68689517d0207b67707b68789517d8207b6780007b6888009517e0207b6790007b6898009517e8207b67a0007b68a8009517f0207b67b0007b68b8009517f8207b67c0007b1888007b68c8003307600101951618317b674801492650010849266801951810217b68580149266001089517a83195186032501052f23a82659800826ba0008266900033070333083309645a3300540a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b790a28040a019518c0207b874095170021951618317b679000821788007b6798003307f001017b87509517a8317b876049185801491870491868019517603295181021501056653a82655001826b58018266480133070433083309645a3300580a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515c02082573082583833090a147b574895170821951618317b67900033071a7b67980033071802017b575049155801491570491568019517a8317b5760951760329518102150105ad33982655001826b58018266480133070333083309645a33005c0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b013307340001951618317b6790003307127b6798003307a800019518c0207b8750491858014918709519a8317b896049186801951760329518102150105e4b3982655001826b58018266480133070433083309645a3300600a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019519c02082977b17788297087b17708297107b17688295188298207b186080974882962849218000ff0f9559ff0f98990c3308107b1788000a1701510717330ab41201330702330b3e330833090a6428e6007b165882178000c8670798770c821978c879097b15789557ffff0084770000ff957500000298580c821788000a1701510717330a761201330702330b3e330833090a6428a00082168000821770c8760698690c846700f014080000fefe00000000c9780898880c821788000a1701510716330a3a1201330702330b3c330833090a642861330900000182178800821868821a780a1601510716330afc1101330702330b3e330833090a642839821788008218606459821a580a1601510716330abe1101330702330b3e330833090a642814330a901101330702330b2e330833090a64019518183133074c00017b8790003307127b8798003307a800019519c0207b9750491958014919709518a8317b986049196801951760329518102150106290379517183182755001827b58018276480133070433083309645a3300640a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b0133050810951710213308330908105010665c3a951618314906951718217b670849161049161895171021330a0633087b15786459330b330c0a12017b6768025117ff7e0233071a7b17880033075002017b177033079002017b176833077000017b1760330540000395550000103307e002017b1758282795161831826b95bb017b6b95171021330a063308821978330c0a12017b6768025117ff26027b669000821788007b679800951880337b68a0007b67a8008217707b6748014926500102492668019518a8317b68580149266001029517403195186032501068653695171831827630827b388277287b17800033070433083309646a33006a0a6401821b800082179000c8b70753370000f01a8257c97508ab680fc9b708018259ab79f27b58019518c020808750808854951918317b97107b98183309010a17951918317b974802951728317b974801821788007b975001951830317b9858017b976001951860337b9868017b9770018217687b97900049299800034929b000951760327b97a0004929a80003951740319518a83150106cad3595171831827630827b388277287b17800033070433083309646a33006e0a6401821b800082179000c8b70753370000f01a8257c97508ab680fc9b708018259ab79f27b5801951b183182b91882b71082b808951a10217bba780297990c7bb98802330a00100a16951918317b970801951728317b974801821788007b975001951890337b9858017b9760019518a0337b9868017b9770018218607b9878017b978001951820327b9888017b9790018217587b97900049299800054929b000951760327b97a0004929a80005951740319518a831501070d53495171831827630827b388277287b17800033070433083309646a3300720a6401821b800082179000c8b70753370000f0defd8257c97508ab68d2fdc9b708018259ab79f17b58330a01ab79e928bdfd33073800017b67283307127b67303307a800017b674801492650010149266801951840317b68580149266001019517a831951860325010744c3482659800826ba0008266900033070433083309645a3300760a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b790195161831826918959a018267103308f0ef0fdb9a087b68183309010a177b6720951728317b674801951730317b675801951738317b67680133071a7b6750017b6760017b67700133074803017b679000951760327b67a00049269800034926a800034926b000951740319518a8315010789233826530826b3882662833070433083309645a33007a0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b019516183149165849165049164849164049163849167049167814070000ffff000000007b672814070000fefe000000007b6730826749268000492688004916687b676033075c00017b6708013307127b6710013307a800017b674801492650010149266801951820327b68580149266001019517a8319518603250107ccd3282659800826ba0008266900033070433083309645a33007e0a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b0195174031951618317b67080133071e7b67100133079803017b674801492650010149266801951820327b68580149266001019517a8319518603250208000453282659800826ba0008266900033070433083309645a330082000a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b790195131831823228823930823438823040823b48823c50823658823560492390000000018237687b3298008238707b39a0008239787b34a800823a80007b30b000823288007b3bb8007b3cc0007b36c8007b35d000951518317b57d8007b58e0007b59e8007b5af0007b52f80033071a7b17783307c803017b177033064000039566000010019517c0208277489518a8310a197b1880007b570001951708217b5748018217787b575001951818327b5858017b576001951800217b5868017b5770018217707b570801492510010349252801951760327b57180149252001039517a033951820325020840011319517183182759002827b9802827788027b17880033070433083309645a330086000a6401821b880082179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b680195151831825700015107b90085770382188000858864d48707520737ff951740313309689518b0315020880014338257607b1780008257687b17608257707b1788008257787b1768951718318275800049274001492738014927300149272801492720014927180149271001492708019517603233090001330850208a0074339517c02082774895182032821960821a88000a159517c02082774895186032821968645a0a1595182032951a60328217800082198800645b951518310a642892fe33072c00017b5788023307127b5790023307a800017b5748014925500101492568019518a0337b5858014925600101951720329518603250208c00ca2f9517183182751001827b18018276080133070433083309645a33008e000a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b790a28040a019518c0207b874095170021951618317b67880233071a7b6790023307f001017b6748019517a0337b6758014926500101492660010149266801951720329518603250209000332f82651001826b18018266080133070433083309645a330092000a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b019517c020827748951518318258482550027a575402492548027b18705118ffc503330814090000fffe000000007b1968140700f0ffffff0f00007b176033071a7b17800033077000017b17583307e804017b1750491148f0ef0f3307067b17403307167b173833076805017b17303306400003956600001033076400017b17283307127b17203307a800017b171833070e7b17103307a805017b170828148219880095980195151831821770aa7935037b5858027b18880097890c9517c020827748825808821a68c8a909821a60d2a9097b596002330a00100a157b576802951708217b574801821780007b575001951820317b5858017b576001951878337b5868017b5770018218587b5878017b578001951880337b5888017b5790018217507b570801492510010549252801951860327b58180149252001059517a0339518203250209400a02d9517183182759002827b9802827788027b177833070333083309645a330096000a6401821b7882179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b6801951a183181a7540281a858029519c0207a9750821748be87077aa774027a9754951710217ba77802492a800208951790337ba748018217407ba7500195176c337ba758018217387ba7600195188c337ba868017ba770018217307ba70801492a100103492a2801951760327ba71801492a2001039517a0339518203250209800d72c9517183182759002827b9802827788027b177833070433083309645a33009a000a6401821b7882179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b6801951a183182a7580282a8ab8711821788007aa7480295186433280c9589ff95186833ab970d9517c0208177587a87018217287ba788028217207ba790028217187ba74801492a500101492a68019517a0337ba75801492a600101951720329518603250209c00282c9517183182751001827b1801827708017b177833070433083309645a33009e000a6401821b7882179000c8b70753370000f01a8267c97608ab580fc9b708018269ab79f27b680133080810951710210a13951818317b8778020a9518c0207b874095187033951918317b984801821780007b9750017b9858017b976001951890337b9868017b977001951800217b9878017b978001951760337b9788018217107b9790018217087b970801492910010549292801951860327b98180149292001059517a033951820325020a000592b9517183182759002827b9802827788027b177833070433083309645a3300a2000a6401821b7882179000c8b70753370000f0e1fc8267c97608ab58d5fcc9b708018269ab79f17b68330a01ab79e928c0fc9517643395186833951960337b59480133090e7b5950017b5758017b5960017b5868017b59700133070804017b570801492510010349252801951860327b58180149252001039517a033951820325020a400b42a9517183182759002827b98028276880233070333083309645a3300a6000a640182179000c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515c0208257480a1a951618317b6778020a7b5740951708217b674801951790337b675801951700217b67680133071a7b6750017b6760017b67700133075804017b670801951760327b67180149261001034926200103492628019517a033951820325020a800ff2982659002826b98028266880233070433083309645a3300aa000a640182179000c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b013307600001951618317b6788023307127b6790023307a800017b6748014926500101492668019518a0337b685801492660010195172032951860325020ac00742982651001826b18018266080133070433083309645a3300ae000a640182179000c8670753370000f03033074000039577000010018278c98709ab591ac9680901827aab8af27b79330b9517603333080c28abea9517603333080c28a1ea00951108f87b10f0077b15e8077b16e0079511a8fb7b18407b17389518ff079588b103491148ffffef33075000017b87183307127b872033070006017b17b0014921b801014921d0019518ff079588c9037b18c0014921c801019517a8009518b0015020b000af288215b000821bb8008216a80033070433083309645a3300b2000a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b01821840531808be02821638520606286b259567045207062862257c67047b17307c67057b17287c67067b17207c67077b17189589f89566085109457d673305015907408477ff003305025327c0002d3305035327e000253305045327f0001d3305055327f800153305065327fc000d8877fe009a750801ae59092847023305017b154064676458646564965020b400c234645982154051072b02e45607c957075317602102c895059576a09557607b174051064f7d783305015908378489ff003305025329c0002d3305035329e000253305045329f0001d3305055329f800153305065329fc000d8898fe009a850801ae560628872464585020b600553428073305330701e45608c95808e47808c97808330920ac98ad01821940c89505c857079585e09577207b17405105537d783306015908378489ff003306025329c0002d3306035329e000253306045329f0001d3306055329f800153306065329fc000d8898fe009a860801ae6506280f2464685020b800dc33ac560c284701330654054201821740c867077c78330a0151080c491140491138288200e46508c96808957501e4a807957bff5518020a3306330728557d573306015907378477ff003306025327c0002d3306035327e000253306045327f0001d3306055327f800153306065327fc000d8877fe009a7608017b1b40ae6b06288823645764685020ba005133821b4001c865057b1538e46b08c96808e678077b17400133074000019518ff079588b1037b87183307127b872033070006017b17b0014921b801014921d0019517ff079577c9037b17c0014921c801019517a8009518b0015020bc0006268215b000821bb8008216a80033070433083309645a3300be000a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b01821840521824338217388078200a0e33083307000001280a3308330700000101951158048210f0078215e8078216e0079511f80732008217289777087b17288217209777107b17208217189777187b171833074400019518ff079588b1037b87183307127b17107b872033070006017b17087b17b0014921b801014921d0019518ff079588c9037b18c0014921c801019517a8009518b0015020c0001f258215b000821bb8008216a80033070433083309645a3300c2000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b790146115782193880977b1758951757330801821a400a03821730821828d487077b1730821720821818d487077b172833073000019518ff079588b1037b87188217107b87208217087b17b0014921b801014921d0019518ff079588c9037b18c0014921c801019517a8009518b0015020c40065248215b000821bb8008216a80033070433083309645a3300c6000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b7901821730821828d487077b17304611626a461163614611646d461165444611664f461167544611686a4611690d46116a4a46116b1946116cd10046116d990046116e5046116f5746117013461171fc0046117265461173f50046117431461175034611768e0046117773330bf100781b78461179d80046117a850046117b6446117c5646117d3246117ec8003306ae0078167f4621800050330c3c781c8100462182004f462183000c462184004d462185005e462186001946218700a70046218800bf0046218900a90046218a00bb0046218b000f46218c00a40046218d00960046218e00870046218f004746219000e600462191003d781c9200781b930046219400e700462195004a462196004946219700dd0046219800c40046219900a60046219a00ec0046219b00a80046219c009a0046219d006a46219e006f46219f00334621a0009d004621a100a3004621a200334621a3007f4621a400d2004621a500eb004621a600554621a700079517a8003309000133085020c800cd2533073400019516ff079566b1037b67183307127b67209517587b672833071a7b673033071006017b17b0014921b801024921d0019518ff079588c9037b18c0014921c801029517ff079577f9039518b0015020ca004a22826550826b5882664833070433083309645a3300cc000a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b018217589577ff5417090728771c9777023308000001c8870781773207951862330903951aa800330c0001821730330b0a029515ff079555b1037b57709577018877019777017b17209517587b571833091a7b59209517ff07957721047b57287b19287b593033076806017b17b0014921b801034921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020d0006a21825650825b5882554882172033083309646a3300d2000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267703308015020d4009d2e951762330803951965330a030a039518587b68189518ff07958829047b68288218287b68207b68303308b006017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67789577018877019777017b17289517ff079577f9039518b0015020d600a620826550826b5882664882172833083309645a3300d8000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b1038257783308023306025020da00d62d951862330903951aa800330c0001821730330b0a027b5780009577fd8877019777017b17209517587b571833091a7b59209517ff07957731047b57287b19287b59303307f806017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b0015020dc00d51f825650825b5882554882172033083309646a3300de000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b103826780003308055020e000072d95176233080a0f9518587b68188218287b68207b683033086007017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b679577098877019777017b17287b66289517ff079577f9039518b0015020e200201f826550826b5882664882172833083309645a3300e4000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308063300b00128502c951862330903951aa800330c0001821730330b0a029515ff079555b1037b57789577fd8877019777017b17209517587b571833091a7b59209517ff07957729047b57287b19287b59303307a007017b17b0014921b801034921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020e8004a1e825650825b5882554882172033083309646a3300ea000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267783308015020ec007d2b9517623308033309330a0a039518587b68189518ff07958831047b68288218287b68207b683033080008017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780009577fd8877019777017b17289517ff079577f9039518b0015020ee00871d826550826b5882664882172833083309645a3300f0000a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b103826780003308023305025020f200b62a951862330903951aa800330c0001821730330b0a029518587b681833081a7b68207b683033083008017b18b0014921b801034921d0019518ff079588c9037b18c0017b15c8017b679577018877019777017b17287b66289517ff079577f9039518b0015020f400c21c826550826b5882664882172833083309645a3300f6000a6401821748c8670753370000f0580233074000039577000010018278c98709ab594102c9680901827aab8af17b79330b01ab8ae9282c023306039517683308030a0e9515ff079555b1037b57788877019777017b17209517587b571833081a7b58209517ff07957729047b57287b18287b583033078808017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020fa00041c825650825b5882554882172033083309646a3300fc000a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267783308015020fe0037299517683308030a0d9518587b68189518ff07958831047b68288218287b68207b68303308e808017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780008877019777017b17289517ff079577f9039518b00150200001481b826550826b5882664882172833083309645a330002010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b10382678000330802330502502004017728951788003308030a0d9518587b681833081a7b68207b683033083009017b18b0014921b801034921d0019518ff079588c9037b18c0017b15c8017b679577018877019777017b17287b66289517ff079577f9039518b001502006018f1a826550826b5882664882172833083309645a330008010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308053300b00128bf273306039517683308030a0f9515ff079555b1037b57688877019777017b17209517587b571833081a7b58209517ff07957719047b57287b18287b583033077809017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150200c01c719825650825b5882554882172033083309646a33000e010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b10382676833080150201001fa269517683308030a0d9518587b68189518ff07958821047b68288218287b68207b68303308c009017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67708e779777017b17289517ff079577f9039518b001502012010d19826550826b5882664882172833083309645a330014010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b103825770330802330602502016013d26951888009519a800330b03821730330a0a017b57789577018877019777017b17209517587b571833091a7b59209517ff07957729047b57287b19287b59303307080a017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b001502018014018825650825b5882554882172033083309646a33001a010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b10382677833080550201c0173253307e8039518620a069518587b68189518ff07958831047b68288218287b68207b68303308580a017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780009577068877019777017b17289517ff079577f9039518b00150201e018017826550826b5882664882172833083309645a330020010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b1038257800033080650202201b22433079a029518683309030a1b7b17289577048877019777017b17189517ff07957721047b574833071a7b17207b57503307c00a017b17b0014921b801024921d0019517ff079577f9037b17c0014921c801019517ff079577c9039518b00150202401c316825620825b2882551882171833083309646a330026010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b790133080782172850202801fe239518683309038217300a1b9516ff079566b1038218207b68503308180b017b18b0014921b801024921d0019518ff079588f9037b18c0014921c801017b678877019777017b17207b66489517ff079577c9039518b00150202a011716826520826b2882661882172033083309645a33002c010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79013308088217283300b001284e233306039518689519a800330b03821730330a0a017b17a8019577fd8877019777017b17209517589515ff079555b1037b571833081a7b58209517a8017b57287b18287b58303307500b017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b001502030014d15825650825b5882554882172033083309646a330032010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79018217a8013308015020340187229517683308030a0d9516ff079566b1039518587b68189518ff07958819047b68288218287b68207b68303308c009017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67688e779777017b17289517ff079577f9039518b001502036019214826550826b5882664882172833083309645a330038010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b10382576833080233060250203a01c2219518688217300a0c7b57709577048877019777017b17209517587b571833081a7b58209517ff07957721047b57287b18287b58303307980b017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b00150203c01cf13825650825b5882554882172033083309646a33003e010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267703308055020400102211407ffffffffffff0000951a6833083309330b0a059518587b68189518ff07958829047b68288218287b68207b68303308c80b017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67789577048877019777017b17289517ff079577f9039518b001502042010413826550826b5882664882172833083309645a330044010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b1038267783308065020460137209518683309038217300a1b7b6780008877019777017b17209517ff07957731047b674833071a7b17287b67503307f80b017b17b0014921b801024921d0019517ff079577f9037b17c0014921c801019517ff079577c9039518b001502048014b12826520826b2882661882172033083309645a33004a010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019516ff079566b1038267800033080750204c017d1f9518683309038217300a1b8218287b68503308400c017b18b0014921b801024921d0019518ff079588f9037b18c0014921c801017b679577098877019777017b17287b66489517ff079577c9039518b00150204e019b11826520826b2882661882172833083309645a330050010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308083300b00128cb1e3306039517683308030a0e9515ff079555b1037b577033080150205401af1e8257708877019777017b17209517587b571833081a7b58209517ff07957721047b57287b18287b583033078808017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150205601c710825650825b5882554882172033083309646a330058010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019517683308030a0d9519ff079599b1039518587b98189518ff07958829047b98288218287b98207b98309519ff079599b1033308780c017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b97788e779777017b17289517ff079577f9039518b0019515b00150205a010d109517ff079577b103827650827b588277487b172082172833083309646a33005c010a6401821c20821748c8c70753370000f02533074000039577000010018278c98709ab690fc9c80901827aab8af27b79019517ff079577b10382777833080250205e01321d3309000a9517b001330850206001c31233065001951868330920645750206201ff119566ff9555205206ec9518b00133070a069515ff079555b1037b5780008877019777017b17289517587b574833071a7b57509518ff07958831047b58587b57603307b80c017b5718491520034915389517ff079577f9037b5728491530029517ff079577b1039518ff079588c90350206401110f825608825b10825582172833083309646a330066010a6401821748c8570753370000f0790533074000039577000010018278c98709ab696205c9580901827aab8af17b79330b01ab8ae9284d053306039518689519a800330b03821730330a0a019515ff079555b1037b5780009577fd8877019777017b17209517587b571833081a7b58209517ff07957731047b57287b18287b58303307000d017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150206a01470e825650825b5882554882172033083309646a33006c010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267800033080150206e01791b9517683308030a0d9518587b68188218287b68207b68303308c009017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b678e779777017b17287b66289517ff079577f9039518b00150207001950d826550826b5882664882172833083309645a330072010a6401821748c8670753370000f0960133074000039577000010018278c98709ab597f01c9680901827aab8af17b79330b01ab8ae9286a013306039517683308030a0f9515ff079555b1037b5780008877019777017b17209517587b571833081a7b58209517ff07957731047b57287b18287b583033077809017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150207601d60c825650825b5882554882172033083309646a330078010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267800033080150207a01081a9517683308030a0d9518587b68188218287b68207b68303308300d017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b678e779777017b17287b66289517ff079577f9039518b00150207c01240c826550826b5882664882172833083309645a33007e010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019517ff079577b10382773308023300b00128541933060395176833080333098f03330a8f030a098e789515ff079555b1037b57709788017b18209517587b571833081a7b58209517ff07957721047b57287b18287b58303307880d017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150208201550b825650825b5882554882172033083309646a330084010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b10382677033080150208601881895176833088f0333098f030a0a9518587b68189518ff07958829047b68288218287b68207b68303308c80d017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67788877019777017b17289517ff079577f9039518b00150208801950a826550826b5882664882172833083309645a33008a010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b10382577833080233060250208c01c51748058f034815084815048f03330801330901951aff0795aab103330b0133070a057b5780008877019777017b17289517587b571833071a7b57209518ff07958831047b58287b57303307080e017b17b0014921b801034921d0019517ff079577c9037b17c0017b16c8019517ff079577f9039518b00150208e01be09825650825b5882554882172833083309646a330090010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019517ff079577b103827780003308053300b00128ec163306039517653308033309330a0a039515ff079555b1037b57689577018877019777017b17209517587b571833081a7b58209517ff07957719047b57287b18287b58303307500e017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b00150209401ed08825650825b5882554882172033083309646a330096010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b103826768330801502098012016951765330803951962330a030a039518587b68189518ff07958821047b68288218287b68207b68303308800e017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b67709577018877019777017b17289517ff079577f9039518b00150209a012908826550826b5882664882172833083309645a33009c010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b10382577033080250209e015c153306039517653308033309330a0a037b57789577fd8877019777017b17209517587b571833081a7b58209517ff07957729047b57287b18287b58303307b00e017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020a0016207825650825b5882554882172033083309646a3300a2010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019516ff079566b1038267783308055020a4019514951865330903951aa800330c0001821730330b0a029518587b68189518ff07958831047b68288218287b68207b68303308f80e017b18b0014921b801034921d0019518ff079588c9037b18c0014921c801027b6780009577018877019777017b17289517ff079577f9039518b0015020a6019606826550826b5882664882172833083309645a3300a8010a6401821748c8670753370000f02533074000039577000010018278c98709ab590fc9680901827aab8af27b79019515ff079555b103825780003308065020aa01c8133306039517653308033309330a0a037b579577018877019777017b17289517587b571833071a7b57207b55287b57303307280f017b17b0017b16b8014921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020ac01da05825650825b5882554882172833083309646a3300ae010a6401821748c8570753370000f02533074000039577000010018278c98709ab690fc9580901827aab8af27b79019517ff079577b10382773308075020b0010e139518a8008217300a0464759517ff079577b1037b757833080864575020b201ed128857019777017b17289517589519ff079599b1037b971833081a7b98209517ff07957729047b97287b18307b98309515ff079555b1033307600f017b17b0014921b801034921d0019517ff079577c9037b17c0014921c801029517ff079577f9039518b0015020b401f704825650825b5882554882172833083309646a3300b6010a6401821748c8570753370000f02733074000039577000010018278c98709ab6911c9580901827aab8af27b790a28040a019516ff079566b1037b6780003308095020b80125129517ff07957731047b67488217307b67503307b00f017b17b0014921b801024921d0019517ff079577f9037b17c0014921c801019517ff079577c9039518b0015020ba015404826520826b2882661833070433083309645a3300bc010a6401821748c8670753370000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b018219405519212101330519000333071900038218385020be016d068218583a090000031407abaaaaaaaaaaaaaaca7807ae9738330733511809270a08330ad00f01330703330b11330833090a6482175895772a3308073300c0012839113308075020c0013311320764570a109515ff079555b1037b578877019777017b17409517587b571833071a7b57207b55287b57303307e80f017b17b0014921b801024921d0019518ff079588c9037b18c0014921c801029517ff079577f9039518b0015020c2014803825650825b5882554882174033083309646a3300c4010a6401821748c8570753370000f03133074000039577000010018278c98709ab691bc9580901827aab8af27b79330b3307190003330820285edd33071900033308202853dd00000000009511887b10707b15687b16600a7b173308045020c6015b1064177b175033071a7b175833073810017b1720491128024911409517507b1730491138019517089518205020c801a002821510821b1882160833070433083309645a3300ca010a64019568ffffef53380000f02733074000039577000010018278c98709ab5911c9680901827aab8af27b79330b013307000001330882107082156882166095117832009511b87b10407b15387b1630c88909ac895364758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a1864695020cc0133821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206495647251087a82a70851077d82a9105109ab0082a833064000033303000010c8360601826ac85a07aca7d000957b0188bc01d8b30bd4cb0b520bc000826bababe57b67330c7b1218330a400003330b0000107b1ac8ba0ac97a077b17107b180864965020ce01d3035436000010980082121882181033077b280828b50049120833070128ac0033094000033307000010c8790901829ac85a08aca85f958b0188bc01d8b70bd4cb0b520b50829bababe77b98330c01ababdf283133094000033307000010c8790901829ac85a08aca82b958b0188bc01d8b70bd4cb0b520b1c829bababe77b98330c013307400013c9870833077b280828393307017b27082831646c82179577000010821218821608018278c98709ab6911c9c80901827aab8af27b79330b0182181033077b2808017b25107b2782103082152882162095113832009511b87b10407b15387b163095880151085464758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a1864695020d0016cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206489828a086475510a3582983307958b080182bcc8c70795aaff95bb10520af5829a18510a248288088e88887a1085aa01d4a808897ae0a80852080a3307330801284a977701015107405707796452330b4000033308000010c88b0b0182bcc87c0aacca5f95a501885601d85805d4650552055082b6abc6e77bba3308400013c9a80864252806330801017b177b1808491110330858100164175020d2019e0652072282171082180882197b57107b58087b598210308215288216209511383200000000827233090000f0952affffefac9a288277083309400003959900001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972b7b1a825708c8a70764695020d8014f018217c876067b56103307821018821510821608951120320064577b1864a864695020da016ffc8218825a1028c59511d87b10207b15187b16106486838833098000647aae982c82a81082a7ab781364a764a55020de0104fe645a8258100182a708c8870778769588017ba81028ac008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672e7b1a82a708c8570795180c64695020e0013fc8560682177b7610013307821020821518821610951128320064a76458646964a55020e2015ffb645a82551028c2648a330858100164a928cd049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200531910488d7a84aa07c8a70b510a0e647c0178c895cc01acbcfbc9a903843cf8c8cb0a580c1d8482ff0014090101010101010101ca920c017bbc95bb08acabfb84390752090a2813647a51090fc8a9090178a895aa01ac9afb3200827701289511a07b10587b15507b16487b19087b18987a04330927532a71028100330927951b463a080800037b1818491110f0d80033037b143305c810013300ffe0f505016474821718d6740798770b821810c08702c8420a97a230982832ca3808988c119888108488fe0796cc9cc8ca0a97aa3198aa30c858087c8c7c8801c85a0a7ca6017caa78b8ff78bcfe78b60178ba9599fc95bbfcac40ac5417633b97783098883296887b14988811968a9cc8a7079777319877309599fe330ac81001c8a7077c7a017c77951b21c89b0b78ba0178b764870155170a149599ff951821c89808837730788728219777019599fe3308c81001c887077c78017c77951a21c89a0a78a80178a701951b21c89b0b9a9c2733098810018217088218330a5020e8011382105882155082164895116032009511987b10607b15587b16507b1b1851084f807634846801330b2b3305000011db8b057b1528c8c8028468045108427b19303308510a1a64a5017d9b89bbc085bb01c8b8089555ff9599015205efc882027b1a3882787b1c20520823284181763495c2014911282d8468045208c44911307b1a3882787b1c20510824827508ae521e8466085206517c7938c9250a5a1901a4005209b1007b1a1028b00082752082762864576468821928821a30821b385020ea0176013308015207bf00826c186457821818821920821060821558821650951168320c7b12408178307b18087c79387b19827920827628481730307b1710461738017b194864976468821928821a30821b385020ec012101520769821740c97505955501019555ff5105cb00826920330830821748b49002ee015107eb28445219021298a90195a8019888017b1810280864a9491110018278207b18488276288177307b1740959501019555ff510528826920821748821840b49002f0015107ec330801016487821060821558821650951168320082154864576468821928821a30821b385020f2018e003308015207d7826a186457821818821920b4a002f4013308015207c18217109a777b17383305ff01821738c857075117ff45826920821748821840b49002f6019555015107e52839826a18821748821818821920b4a002f80133080152077eff33088217108219087a79308219787938286aff821510821710d87508285eff821710d875082855ff9511d87b10207b15187b1610839c330200001164a66485647aaa2c21825c2064a764987b1b087b1ab4c002fa01821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b167049116020330a03781a688296204911304911407b17507b185851060a018297285107790149112882957b19088298107b18189578ff9788039888039588017b189555089678389566183307e6017b1710017b18208259510918821a588217508258f882aa18b4a002fc01520755018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49002fe015207bb009555108218209588c89566388217289577017b1728520834ff286b829718510773829510330a977804c858087b18207b190882969577ff9777049877049577017b17956608017b1a288269510917821a588217508268f882aa18b4a00200025207588257825908951830b490020202520748956610955510821a2895aa01821720ab75c5821908821a829708ac7a0d282d330a829708540726829797a804c88709821a58821750829882990882aa18b4a002040251070833070128053307018210800082157882167095118800320032009511807b10787b15707b166864923300330b33051403fffefefefefefefe330a0a0a0a0a14040a0a0a0a0a0a0a0a8279107b194882797b19388277087b173033076800017b17083a071000037b17607b18589588087b18330c0a7b12207b13187b1410283b6406c889077c77ff9577f688770101821a4878a7821730827a18821738b4a0020a02645b8212208213188214106460330c0a821540520764018457ff00520758017b1b50ae020a28ef00ac02ec00c90208821658c806065518101daa02d800330a01c8a6077c77aac7a50095aa01aba8f428c200956907849af8c96a07d36a0a88aa01887b01d4ba0a510a453307958af0821bc80b0b2808821bc80b0b01c8760c82ccc87b098299d34c05c83505e0c50cd34905c83505e09509d4c909821c60d2c90952091f957710ae7ad52816c8a60b7cbbaacb5195aa01aba7f5958af0ae7ab9aa879b00330ac87606c97208c90808330c0a821b5001c8a6097c99aac90b95aa01aba8f5282dc87a0a01c80a0a95a001ae2a38ff821758c87a0a7ca7abc72cff2862821b50c80a0a95a001ac2ae9281aff6420014911400164b56426aa2b578217487c77510723821730827a183309048217388218087b1028b4a0020c02821b50821028520733c9b609821858c8b808abb68efe640633072895fe6420821b5028b4491140640564068217487c775207b928d633072806330701018210788215708216689511800032009511d87b10207b15187b16108275107c59827b827608510933826a187b1808330868000133090464b77b1bb4a0021002821808821b510714330701821020821518821610951128320083879577f68877017857826c2064b7821020821518821610951128320c648a330890100164a92899fb951170ff7b1088007b1580007b167864757c7708648b33080133060151071d7856084615090164578210880082158000821678951190003200649a825c80c7347c580984790452094551083282c82882c7208283183308c0100133090264a67b1b107b1c08b430021402821c08821b10646a3308013306015207a764b764c8b4a00216023308016476289652083782c82882c7208283183308c410013309013306017b1a7b1b107b1c08b430021802821c08821b10821a330801520765ff81c7340133060178163782c82082c9287b18187b19209518377b182881c8307cc93882c382c40882c01082c2187a176c7a18687819707b13387b14407b10487b12509517187b175833079010017b176095183864b7b4a0021a02520721821860821758828a183308c21001330902b4a0021c02647633080128e9fe33080128e3fe51089b0064797c77510791005127ff0090006c7a570a09330a330828735527c0000d330a01330b80284a5527e0000e330a02330b40ff283c5527f0000e330a03330b20ff282e5527f8000e330a04330b10ff28205527fc000e330a05330b08ff2812887afe00330b04ff93ab02ff85aa0701ae8a2b3308c8b70764ab01c8b90c7ccc97880895bbffd4c808520bf28aa903cf9707c88707320032000000009511f8fe7b1000017b15f8007b16f0007b1778180f7b171095160f33050195170f330801951910330a080a037b1660330722027b176864177b177033071a7b1778492180000249219000024921a000140820000000100000007b18a8004621b000034921b800024921c800027b15d8007b18e0004621e8000333081013017b183049113802951880007b1850491158029518607b18404911480295171895183050201e02d5f1821520821b2882161833070233083309645a330020020a640133070000f09568ffffefac782433074000039577000010018278c98709ab5911c9680901827aab8af27b79330b01821000018215f8008216f0009511080132009511d07b10287b15207b16186486828828826a20828b186475330888100133090164a7b4b00224027b167817084611097b151033092a02641795181050202602e8fc3307017c180852081b8217827828827720828a183308c51001330901b4a00228028210288215208216189511303200951178ff7b1080006482808834827784891052091b8488205208467c77330801642982108000951188002866f47c77330a810095187f3303570164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e128317c77330a810095187f3303370164ab847a0f97773898773c88ac0a330930dac309bea90978899588ff95baff5207e195b7fe562780002b9aac8100641bc87b0b3309c61001330801330a02642750202c0213f582108000951188003200002124a29424a58814c99224292915c992242929095142528868922425098924493449524892499284444b92224a92942252244b922425a9489624494a921025248588469424a924a58814c99224292915c99224292909514252886844499252448a64499294948a6449929494842821294434a22449292245b224494a4a45b224494a4a42949014229a242529a428494a42520a492924a5909442520a492924a5909442520a492924a590944292928444921411111111811089102122424448922a8d24248425596a8848222591909090901099440a499224851a89882842442244888810112249aa341284b0244b23222292aa914484884488101121224492546924086149961a518888a821424422442291880811912a8d04212cc9522324242444449224222249120991242549924444221249924849922449249144444444444444448488101121224444aa341284b0244b3b12111121914844848848954682109664692495884884442212112222551a09425892a586884488442211112222551a09425892a5519224491244124d48aa24922421844413922a91240248a209495588a4094955a43421a90a4935422442241289881011912a8d04212cc952238a10459248a91a21111212124248518a941a2122222211222244844812a9d2880425591a49242922222222222211222244844812a9d2880425591a4922125144444444444422222211222244844812a9d288044a64a9494812224444880811912a8d04212cc9d248129294888888444488881022222449954682109664a9912449024800292209910811222244848848954682109664a9119108112222440411912a1a09425892a59124491248241211111111111191848430124544242222221221224244101111a9a211094ab2342212494422482489242222222222a220128922918a88284a88448810112122888848158d04212cc9d28e44442244440811114444aa6824086149961a892222a100124012212141928484109284242145221191489224a288888888884844442442448488202222a9a2890425591a119124121122121189884884880811414444524513094ab234a2444489449a482442448488202222a9a2890425591a51c4484444444444444424122122424410119154d1440225b2d42422221111112244448808222252452341084bb23452c4444444242242448410114144a48a4682109664a92122112244448808222255341284b0244b4512c98888482282902444888808114144a48a2641084bb2d4842449922449929444424242424264d254052592902429898484848484c8a4a09a2489244952120909090909914941522425499224519544424242424264920a3249922122498810111122828848154d82109664a989a442851111519224494244928444888808114144a48a2641084bb23429494a922409114912212222440411912a9a04212cc9d22489888888880821224284881091102222444222841042100441088220042122082108822008420841104210841051102292244988101111222248922a9a04212cc9529348422a89484524499224224988101111222248922a9a04212cc9d28824489292882409112222429224228224a9a24910c2922c8d48122411a948922489481222444444440449524593208425591a110952499210212222942489882049aa681284b0244b234a2489484524499224224988101111222248922a9a04212cc9d2882448aa2422494284888810491211419254d124086149964644122411a92449881011112549222248922a9a044258224b4d921491244912912444444484880892a48a2641084bb23422099292882409112222422489882049aa681284b0244b2322092225494284888828491211419254d1240861499646944892229224492292848888881011419254d1240861499646244152129124214244444849440449524593208425591a912488482a49922411494284888888882049aa681284b0244b2392205212912421424444882489882049aa681284b0244b2322412425492292244488880811112449154d8210966469122429220911222242491211419254d12408614996269124928a24494492481222222242440449524593208425591a09922292882409112222424a222248922a9a04212cc9d2882441529224492292840811111111419254d1240861499646244100a94a229224448888084992880892a48a2641084bb23422099214492292244488880811112449154d8210966469442448521222444484922411112449154d82109664694489242922099224492292848888881011419254d124086149962645241149121122444484944444041149922a9a24086149964624414441260549a222224992442421918844444490942a9a044258224b4d92482a229224492292848888881011419254d12408614996464482a42449881011112a4944044952459340084b64a949922222499244240911111121228224a9a24910c2922c8d8804494992102122225492880892a48a2641084bb234a24492445444922489481222222242440449524593208425591a91048928894892102122222449440449524593208425591a91248884242215499224220911222222228224a9a24910c2922c8d884492541149922489481222222242440449524593208425591a9104495212912421424444489244449024553409425892a5114990a44a922449449210111111222248922a9a04212cc9d2882448225249449284081111219224228224a9a24910c2922c8d880449aa9224499210111111222248922a9a04212cc9d28812442a222948928824114922428488881011419254d1240861499676442488481222444484880892a48a2641084bb2d4841012240490240a49952492a08a284992242142444488882049aa681284b0244b8524243f4996a024219124922049aa6808425892a58692a424492a49922491b2144a0248a649d224a9248942c8124912a51242495210484a9284902549925253085992242935a49454215992a5a64c495292249524499248590a4a0248a649d22429a5b2244952929252268590254992524865492848525292f44248425892a52a494a292505252549554129492a4a4a0565529224892492924492482229892491249248a6a424859425495541a95092244a522b4992244952c99294944a692549929524498a92b4244922802c492a595227494a82242488102c4992244924494a5292924412499284a4243592a4929094a449422a24494992240949929496244952521249529224498824a924412225495292944422952448928924214592542649324912922549a92441929290a46412494252928444494a9224499214aaa452282549952435498a4822499244222549929244a6244988244952224992aa9449924892a42a659224252192244994a4242949ca9424092909499224259594242521a99144254955004100494942429292a492644a124a52121149224944532449922429a532a524499224292549a224c994a44c22294a92342a294992842449a2524aa55499244a925492845448499254524a920a2522524a92282251254992849484a4241552491292929094c8244992a42449922409492149424249121541a942524814128544215144644a539224a94744942449522225092102881042440889482491044952454348084bb2d4888892a42485144a1225485292909024459492a4149122599224294945b224495292842821298828") + + core_vm_child_blob = bytes.fromhex("080200080000020000a0004348494c44204e4f524d206e3d206669625f6e5f323d20726573756c743d202861646472323d202861646472313d29206669625f6e5f313d2920726573756c743d4348494c442042415345206e3d4348494c44205752495445206f75745f616464726573733d00003078303030313032303330343035303630373038303931303131313231333134313531363137313831393230323132323233323432353236323732383239333033313332333333343335333633373338333934303431343234333434343534363437343834393530353135323533353435353536353735383539363036313632363336343635363636373638363937303731373237333734373537363737373837393830383138323833383438353836383738383839393039313932393339343935393639373938393900000000000000000100000000000d000000000000000d0001000000000009000000000000001e0001000000000008000000000000002e000100000000000a00000000000000260001000000000008000000000000003800010000000000090000000000000041000100000000000d00000000000000160001000000000008000000000000004e000100000000001800000000000000160001000000000008000000000000001e0000000000000018000000000000000800000000000000200000000000000026000000000000002e000000000000004b598638d6c56d349b10000027028e790300b700c2007601e401ff01cd02e8025e0379030e04a604c5059806bc06ef0619073e0745076f0725084b0852080709190acb0a1e0b3f0b820bae0bc30bec0b040c5e0c130dac0d0b0e1a0e5e0e288101951178ff7b108000808934849a10520a168499205209518077821080009511880028e708817b3309810095177f33025701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842817b3309810095177f33023701649c8bba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a013309026487330868000150100475098210800095118800320000951178ff7b108000808934849a10520a1684992052095182778210800095118800282808827b3309810095177f33025701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000699a9b8100641ac87a0a2842827b3309810095177f33023701649c98ba0484bb0f88b30a330930da3209beb90978799577ff95c9ff64ab520ae295c7fe56278000289a9b8100641ac87a0a0133090264873308680001501008b6088210800095118800320000951100ff7b10f8007b15f0007b16e800491108ffef7b1710330a027b1a551702940048111c019517107b17403307067b174895171c7b17507b1a5833079801017b177049117802492190009517407b17800049218800029517d00095187050100a14048215d800821be0008216d00033070233083309645a33000c0a6401821708c86707532700f00e01330710000395770010018278c98709ab59f900c9680901827aab8af17b79330b01ab8ae928e40097770c140800e0fefe00000000c878087b182081887a182c140900f0fefe00000000c897077b173081777a173cbe87077a171c9517107b17703307067b177895182c7b1880007b1a88009518207b1890007b17980095183c7b18a0007b1aa8009518307b18b0007b17b80095171c7b17c0007b1ac80033073801017b1740491148064911609518707b1850491158069517d00095184050100e2b038215d800821be0008216d00033070233083309645a3300100a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0181171097770c83770000fffe7a17309517307b174082187b184895171c7b17507b18583307b801017b177049117802492190009518407b18800049218800029517d0009518705010129a028215d800821be0008216d00033070233083309645a3300140a6401821708c86707532700f025330710000395770010018278c98709ab5911c9680901827aab8af27b79330b0180173081181c7a78801730330800108210f8008215f0008216e8009511000132009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101632821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206496647351086e82a70851077182a91051099e0082a8330200103304100003c8240701827ac86a05aca5c200955b0188bc01d8b20bd4cb0b520bb200827bababe57b75330c7b1318c95407957700107b17107b180864957b14501018b40354250010940082131882181033077b380828b10049130833070128a800330700103302100003c8720901829bc86b0aacba5d95ac0188c801d8c70cd4c80852084e8298abb8e77b9a330c01abb8df2830330700103302100003c8720901829bc86b0aacba2a95ac0188c801d8c70cd4c80852081b8298abb8e77b9a330c01c9a2079578001033077b380828383307017b37082830645c821895870010821318821508018278c98709ab5911c9c80901827aab8af27b79330b0182181033077b3808017b36107b3782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101a7cfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b1620828a086475510a3582893307959b080182bcc8c70795aaff95bb10520af5828a18510a248299088e99887a1085aa01d4a909897ae0a90952090a3307330901284b977701015107415707746453330900103302100003c8920b0182bcc87c0aacca5b95a501885601d85905d4650552054c82b6abc6e77bbac9a209330a0010c8a90964352806330901017b177b1908491110641750101c030652072282171082180882197b57107b58087b5982103082152882162095113832000000008272330900f0952affefac9a2782770833091000039599001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950102241018217c876067b56103307821018821510821608951120320064577b1864a864695010248cfc8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a550102811fe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950102a34c8560682177b7610013307821020821518821610951128320064a76458646964a550102c7ffb645a82551028c42844049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a87b10507b15487b16407b18987904330827330a6a0001532971027b330827951b3e3a090000037b1910491108f0d80033037b143300ffe0f505016472821710d6720798770b821908c09709c82906976930989932ca39099894119899108499fe07964c9cc86c0c97cc3198cc30c8a9097c967c9901c8ac0c7cc5017ccc78b9ff78b6fe78b50178bc9588fc95bbfcac20ac5417633697793098993296997b14989911969b9cc8b7079777319877309588fec8a7077c7b017c77951c19c88c0c78cb0178c764970155170a149588ff951919c889098377307897281c9777019588fec8a7077c79017c77951a19c88a0a78a90178a701951a19c88a0a9a8b273308680001821733095010321282105082154882164095115832009511987b10607b15587b16508073347b1a20649c84360133022b3309000011843a047b1b28c8b6047b1c30520a10491138827894692b52083528567b18383309510c1b821b38017db58955c0855a01c8a90995ccff95bb01520cefc8940433090000118278db6209510827827a08aea4218438085208507c7638c94a0a7b19185a16019d005206aa007b1a1028a90082752082762864576468821a38821b305010346c013308015207bb00826c186457821820821928821060821558821650951168320c7b1a4064458178307b18107c7a387b1a08827a20827828481730307b17461738017b1a4864a76486821a38821b305010361901520767821740c95705955501019555ff5105c600826920330830821748b49001385107ec28435216021298a60195a8019888017b1810280864a6491110018278207b18488275288177307b1740956601019566ff510627825920821748821840b490013a5107ed330801016487821060821558821650951168320082164864676458821918821a38821b3050103c89003308015207d8825a186467821820821928b4a0013e3308015207c38217109a777b17383306ff01821738c867075117ff42825920821748821840b49001409566015107e62837826a18821748821820821928b4a00142330801520782330882168217107a6730821708786738286fff821610821710d876082863ff821710d87608285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c00144821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b17503307d801017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307307b1710017b18207b19288259510917821a588217508258f882aa18b4a0014652074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49001485207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a0014a5207568257825908951830b490014c520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0014e5107083307012805330701821080008215788216709511880032008948921491225992242525214a45b224494a4a42942984884624498a48912c4992929210a522599224252521ca1442442322425288244912129108911011a9d22408b144969a2480a404909424491291884424221121912422212252a54908b1244b4d82242549484422444244a44a93106249969a9488882849924a922449a42c454900c934499a24952451842c9124512a89a44290942489902549925253842c4992949a282555244bb2d49429494a92a492244912294ba12480649a244d9294ca922449494a4a9914214b9224a5442a4b0a494a4a925e4412624996aa2429a594144a4a92aa4229492a4a4a85322949924412494922492491944492481249245352922265495255282549a224b59224499224952c4949a994569224594992a44e9292109290208225499224892449494a529248224992a4243592a492a4244d122a92a424494a42922425a564499224942449921049524948a424494a499244914a42924c24891449529924c92449244b92524942929248523289249194249154922449922449a14a2a452949aa24a94952441249928444a2922449499249499288244952224992aa9449924892a42a6592242511499244494a9292a44c4992484924499294545292944452238900") + #core_vm_child_blob = bytes.fromhex("2a020008000001010000106d61696e010000004348494c4c200000080001000000000006000000000000004348494c44204e4f524d206e3d206669625f6e5f323d20726573756c743d202861646472323d202861646472313d29206669625f6e5f313d2920726573756c743d0000000000000020000100000000000d000000000000002d0001000000000009000000000000003e0001000000000008000000000000004e000100000000000a0000000000000046000100000000000800000000000000580001000000000009000000000000004348494c442042415345206e3d000000c8000100000000000d00000000000000360001000000000008000000000000004348494c44205752495445206f75745f616464726573733df80001000000000018000000000000003600010000000000080000000000000026000000000000001800000000000000080000000000000028000000000000002e000000000000003600000000000000307830303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839394b598638d6c56d34431200002b028feb0300bc00c70073017e012a028802a00218033303060421049a04b5044c05ee051207e40708083e0868088d089408be0874099a09a109560a790b3c0c900cb10cf40c200d350d5e0d760dd00d850e1e0f7d0f8c0fd00f283502951178ff7b108000648280883484891052092884882052085281778979859801977a2098aa209a77da9a076429821080009511880028220a817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309600101330801330a026427501004d00a8210800095118800320000951178ff7b108000648280883484891052091b848820520845807733080164298210800095118800286b09817a3308810095177f33035701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830817a3308810095177f33033701648b8bac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309600101330801330a026427501008190a8210800095118800320000951178ff7b108000648280883484891052091b84882052084582773308016429821080009511880028b408827a3308810095177f33035701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce22830827a3308810095177f33033701648b98ac0484aa0f88a80a330930da8309bea90978799577ff95b8ff64ca520ce295b7fe562780002a9a8c8100641bc87b0b3309600101330801330a02642750100c62098210800095118800320000951100ff7b10f8007b15f0007b16e800491108ffffef7b177b171033070400017b17d0003307027b17d80033071000017b177049117801492190009518d0007b188000492188000195174095187050100ebd04821648821b5082154033070433083309646a3300100a6401821708c8570753370000f02733071000039577000010018278c98709ab6911c9580901827aab8af27b79330b018218551802990048111c019518107b184033080a7b184895181c7b18503308067b18583308d800017b187049117802492190009518407b18800049218800029517d0009518705010122d048215d800821be0008216d00033070233083309645a3300140a6401821708c8670753370000f0150133071000039577000010018278c98709ab59fe00c9680901827aab8af17b79330b01ab8ae928e90097870c140800e0fefe00000000c878087b182081887a182c140900f0fefe00000000c897077b173081777a173cbe87077a171c9517107b177033070a7b177895182c7b1880003308067b1888009519207b1990007b17980095193c7b19a0007b18a8009519307b19b0007b17b80095171c7b17c0007b18c80033076800017b1740491148064911609518707b1850491158069517d0009518405010163f038215d800821be0008216d00033070233083309645a3300180a6401821708c8670753370000f02733071000039577000010018278c98709ab5911c9680901827aab8af27b79330b0181171097770c83770000fffe7a17309517307b17403307067b174895181c7b18507b175833071001017b177049117802492190009518407b18800049218800029517d00095187050101aab028215d800821be0008216d00033070233083309645a33001c0a6401821708c8670753370000f02733071000039577000010018278c98709ab5911c9680901827aab8af27b79330b0180173081181c7a78801730330800108210f8008215f0008216e8009511000132009511b87b10407b15387b1630c88909ac895264758277977801330a08e4a909e498068568ff98883f5107128259087b1918491120017b17282806491120016417951a18646950101e32821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b16206495647251087982a70851077c82a9105109aa0082a833061000033303000010c8360601826ac85a07aca7cf00957b0188bc01d8b30bd4cb0b520bbf00826bababe57b67330c7b1218330a100003330b0000107b1ac8ba0ac97a077b17107b18086496501020bb035436000010980082121882181033077b280828b50049120833070128ac0033091000033307000010c8790901829ac85a08aca85f958b0188bc01d8b70bd4cb0b520b50829bababe77b98330c01ababdf283133091000033307000010c8790901829ac85a08aca82b958b0188bc01d8b70bd4cb0b520b1c829bababe77b98330c013307100013c9870833077b280828393307017b27082831646c82179577000010821218821608018278c98709ab6911c9c80901827aab8af27b79330b0182181033077b2808017b25107b2782103082152882162095113832009511b87b10407b15387b163095880151085364758277977901330a08e4a808e489068568ff98883f5107128259087b1918491120017b17282806491120016417951a1864695010226dfe821882170851081414080100000000000080aa870d520718007b57087b56018210408215388216309511483200009511c87b10307b15287b1620828a086475510a3582893307959b080182bcc8c70795aaff95bb10520af5828a18510a248299088e99887a1085aa01d4a909897ae0a90952090a3307330901284a977701015107405707736452330b1000033309000010c89b0b0182bcc87c0aacca5995a501885601d85905d4650552054a82b6abc6e77bba3309100013c9a90964252806330901017b177b19084911106417501024290652072282171082180882197b57107b58087b598210308215288216209511383200000000827233090000f0952affffefac9a288277083309100003959900001001829ac9a90bab7b12c92a0b01829cabacf27b9b3308320032009511e07b10187b15107b16086475827a108277c9a7076496ac972a7b1a825708c8a707646950102a41018217c876067b56103307821018821510821608951120320064577b1864a8646950102c7bfc8218825a1028c79511d87b10207b15187b16106486838833098000647aae982b82a81082a7ab781264a764a55010300ffe645a8258100182a708c8870778769588017ba81028ab008b670b48110c52071c9867068677c00078170c84673f8677800078170d33060228638b671052072998670c8677e00078170c97673498773a9577800078170d84673f8677800078170e330603283797672b98773d9577f00078170c97672e98773a9577800078170d97673498773a9577800078170e84673f8677800078170f3306040182a51082a7c95707ac672d7b1a82a708c8570795180c646950103234c8560682177b7610013307821020821518821610951128320064a76458646964a55010346efb645a82551028c42867049511e07b10187b15107b1608531910648d7a84a207c8270b510215648c6475017cca785a95550195cc01acb5f6c82803c929028424f8843807c84b0a51083b58044b973803848038843cf882c58d8884883895cc080182c6d00505cf8609d459097bb995bb0895cc086465acabeb281c647a520921282f58041364380182897bb995bb08958808acabf6c84308842907510914c8a909017c8b78ab95aa01958801ac9af68210188215108216089511203200827701289511a07b10587b15507b16487b19087b18987a04330927532a71028100330927951b463a080000037b1818491110f0d80033037b1433056201013300ffe0f505016474821718d6740798770b821810c08702c8420a97a230982832ca3808988c119888108488fe0796cc9cc8ca0a97aa3198aa30c858087c8c7c8801c85a0a7ca6017caa78b8ff78bcfe78b60178ba9599fc95bbfcac40ac5417633b97783098883296887b14988811968a9cc8a7079777319877309599fe330a620101c8a7077c7a017c77951b21c89b0b78ba0178b764870155170a149599ff951821c89808837730788728219777019599fe3308620101c887077c78017c77951a21c89a0a78a80178a701951b21c89b0b9a9c2733096001018217088218330a50103a1282105882155082164895116032009511987b10607b15587b16507b1b1851084f807634846801330b2b3305000011db8b057b1528c8c8028468045108427b19303308510a1a64a5017d9b89bbc085bb01c8b8089555ff9599015205efc882027b1a3882787b1c20520823284181763495c2014911282d8468045208c44911307b1a3882787b1c20510824827508ae521e8466085206507c7938c9250a5a1901a1005209ae007b1a1028ad0082752082762864576468821928821a30821b3850103c6d013308015207bc00826c186457821818821920821060821558821650951168320c7b12408178307b18087c79387b19827920827628481730307b1710461738017b194864976468821928821a30821b3850103e1901520767821740c97505955501019555ff5105c600826920330830821748b49001405107ec28435219021298a90195a8019888017b1810280864a9491110018278207b18488276288177307b1740959501019555ff510527826920821748821840b49001425107ed330801016487821060821558821650951168320082154864576468821928821a30821b3850104489003308015207d8826a186457821818821920b4a001463308015207c38217109a777b17383305ff01821738c857075117ff42826920821748821840b49001489555015107e62837826a18821748821818821920b4a0014a33080152078233088217108219087a79308219787938286fff821510821710d875082863ff821710d87508285aff9511d87b10207b15187b1610839c330200001164a66485647aaa2c20825c2064a764987b1b087b1ab4c0014c821a821b08647833070152082051061a825c1864a7646864b9821020821518821610951128320c3307018210208215188216109511283200951178ff7b1080007b15787b1670491160203309037819684911304911408286207b175033073001017b17585106060182872851077301330982857b18088288107b18189578ff9788039888039588017b189555089678389566183307387b1710017b18207b19288259510917821a588217508258f882aa18b4a0014e52074e018167107a17607c67187817688167147a17648268f8826751082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18307b17388268e88267f051082652180116977704821818c88707827808821910aa98073308280f827782773308012806330801017b18407b1748826708977704821818c878088287828908951830b49001505207b5009555108218209588c8956638821928959901520836ff2869828718510771828510330a977904c859097b19207b180882869577ff9777049877049577017b17956608017b1a288269510916821a588217508268f882aa18b4a001525207568257825908951830b4900154520747956610955510821a2895aa01821720ab75c7821808821a828708ac7a0d282c330a828708540725828797a804c88709821a58821750829882990882aa18b4a0015651070833070128053307018210800082157882167095118800320089284952494a112992254952522a922549525212a284a410d1889224a58814c99224292915c99224292909514252886844499252448a64499294948a6449929494842821294434222228211221111121094952a54910c2922cb510499224211189100911912a4d02212c91a526092029012425499244221189484422422249444244a44a93208425596a1224499284442442244444aa3409425892a5262522224a92a492244912294b511240324d922649254914429648922895104a924220294912429624494a4d21644992a4d4905252856449969a3225494992549224492265299404904c93a4499252599224294949299342c892244929a4b2a490a4a424e9859084b0244b559294524a0a25254955a194241525a542999424492289a424912492484a22492489249229294991b224a92a94922451925a49922449924a96a4a4544a2b4992ac24495227494a82242488102c4992244924494a5292924412499284a4243592a4929094a449422a92a42449928424494a4b92242929892429499224449254929048499294242591482509493291245224496592249324912c494a2509494a2249c924924452924452929224499224852aa914a524a992a42649114924491212894a9224254926254922922449892449aa522649224992aa94499294442449122529494a923225492225912449525249495212498d2402") + + # t = reverse_bits_32(8) + # tt = '{:08b}'.format(t) + # ttt = count_leading_zeroes(t, 32) + # print(t, tt, ttt) + # import pdb;pdb.set_trace() + + # t = 15 + # tt = '{:08b}'.format(t) + # ttt = count_trailing_zeroes(t, 32) + # print(t, tt, ttt) + # import pdb;pdb.set_trace() + + + bootstrap_service_account = await client.serviceData(block_hash, bootstrap_service_id) + + work_package.items.append(WorkItem( + service=bootstrap_service_id, + code_hash=bootstrap_service_account.code_hash, + payload=blake2b_256_hash(core_vm_blob) + int(len(core_vm_blob)).to_bytes(length=4, byteorder='little'), + refine_gas_limit=6000, + accumulate_gas_limit=6000, + import_segments=[], + extrinsic=[], + export_count=0 + )) + + await client.submitWorkPackage(0, work_package, []) + print("core_vm workpackage submitted") + + new_service = await client.subscribeServiceValue(0, bytes.fromhex("81e47a19e6b29b0a65b9591762ce5143ed30d0261e5d24a3201752506b20f15c")) + async for data in new_service: + corevm_service_id = int.from_bytes(data, byteorder='little') + #print("subscribeServiceValue UPDATE: ", corevm_service_id) + break + print(f"core_vm service id = {corevm_service_id}") + + await client.submitPreimage(corevm_service_id, core_vm_blob, block_hash) + print("corevm preimage submitted") + + new_preimage = await client.subscribeServiceRequest(block_hash, corevm_service_id, blake2b_256_hash(core_vm_blob), len(core_vm_blob)) + async for data in new_preimage: + print("subscribeServiceRequest UPDATE: ", data) + if data is not None and len(data) == 1: + break + print("corevm preimage available") + + + # CoreVM service is activated, create a new workpackage for corevm and provide corevm_child code blob + work_package = await create_workpackage(client) + block_hash = work_package.context.anchor + extrinsic = blake2b_256_hash(core_vm_child_blob) + int(len(core_vm_child_blob)).to_bytes( + length=4, byteorder='little' + ) + work_package.items.append( + WorkItem( + service=corevm_service_id, + code_hash=blake2b_256_hash(core_vm_blob), + payload=b'', + refine_gas_limit=6000, + accumulate_gas_limit=6000, + import_segments=[], + extrinsic=[ + WorkItemExtrinsic.from_blob(extrinsic) + ], + export_count=0 + ) + ) + + await client.submitWorkPackage(0, work_package, [extrinsic]) + print("core_vm_child workpackage submitted") + + + new_preimage = await client.subscribeServiceRequest(block_hash, corevm_service_id, blake2b_256_hash(core_vm_child_blob), len(core_vm_child_blob)) + async for data in new_preimage: + print("subscribeServiceRequest UPDATE: ", data) + if data is not None and len(data) == 0: + break + print("core_vm_child preimage requested") + + + await client.submitPreimage(corevm_service_id, core_vm_child_blob, block_hash) + print("corevm preimage submitted") + + + new_preimage = await client.subscribeServiceRequest(block_hash, corevm_service_id, blake2b_256_hash(core_vm_child_blob), len(core_vm_child_blob)) + async for data in new_preimage: + print("subscribeServiceRequest UPDATE: ", data) + if data is not None and len(data) == 1: + break + print("core_vm_child preimage available") + + work_package = await create_workpackage(client) + block_hash = work_package.context.anchor + extrinsic = blake2b_256_hash(core_vm_child_blob) + int(len(core_vm_child_blob)).to_bytes( + length=4, byteorder='little' + ) + work_package.items.append( + WorkItem( + service=corevm_service_id, + code_hash=blake2b_256_hash(core_vm_blob), + payload=bytes.fromhex("00000000010000000000000001000000"), + refine_gas_limit=5678, + accumulate_gas_limit=9876, + import_segments=[], + extrinsic=[ + WorkItemExtrinsic.from_blob(extrinsic) + ], + export_count=1 + ) + ) + + await client.submitWorkPackage(0, work_package, [extrinsic]) + print("core_vm trigger corevm child vm") + + + + print("FIN!!!!!!!!") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/pyjamaz/rpc/rpc.py b/pyjamaz/transport/rpc/rpc.py similarity index 100% rename from pyjamaz/rpc/rpc.py rename to pyjamaz/transport/rpc/rpc.py diff --git a/pyjamaz/rpc/ws_client.py b/pyjamaz/transport/rpc/ws_client.py similarity index 98% rename from pyjamaz/rpc/ws_client.py rename to pyjamaz/transport/rpc/ws_client.py index 0f5cb9f2..6655528b 100644 --- a/pyjamaz/rpc/ws_client.py +++ b/pyjamaz/transport/rpc/ws_client.py @@ -9,8 +9,8 @@ from pyjamaz.models.common import WorkPackage, WorkPackageStatus from pyjamaz.models.state import ServiceAccount -from pyjamaz.rpc.interface import RPCMethods -from pyjamaz.rpc.rpc import generate_req_id, RPCCallException, jsonapi_request +from pyjamaz.transport.rpc.interface import RPCMethods +from pyjamaz.transport.rpc.rpc import generate_req_id, jsonapi_parse, RPCCallException, jsonapi_request from pyjamaz.utils import base64_encode, base64_decode diff --git a/pyjamaz/rpc/ws_server.py b/pyjamaz/transport/rpc/ws_server.py similarity index 96% rename from pyjamaz/rpc/ws_server.py rename to pyjamaz/transport/rpc/ws_server.py index d4530e3d..0323b48b 100644 --- a/pyjamaz/rpc/ws_server.py +++ b/pyjamaz/transport/rpc/ws_server.py @@ -7,11 +7,12 @@ from typing import Set import websockets -from pyjamaz.rpc.rpc import RPC_REQUESTS, RPC_TYPE_SUBSCRIBE, RPC_TYPE_UNSUBSCRIBE, jsonapi_response, jsonapi_parse, RPCCallException, jsonapi_ws_subscribed, \ +from pyjamaz.transport.rpc.rpc import RPC_REQUESTS, RPC_TYPE_SUBSCRIBE, RPC_TYPE_UNSUBSCRIBE, jsonapi_response, jsonapi_parse, RPCCallException, jsonapi_ws_subscribed, \ jsonapi_ws_response, RPC_ERROR, jsonapi_error -from pyjamaz.rpc.ws_server_subscriptions import SubscriptionManager +from pyjamaz.transport.rpc.ws_server_subscriptions import SubscriptionManager from pyjamaz.settings import DEBUG, RPC_SERVER_MAX_SIZE + if typing.TYPE_CHECKING: from pyjamaz.app import PyjamazApp diff --git a/pyjamaz/rpc/ws_server_subscriptions.py b/pyjamaz/transport/rpc/ws_server_subscriptions.py similarity index 98% rename from pyjamaz/rpc/ws_server_subscriptions.py rename to pyjamaz/transport/rpc/ws_server_subscriptions.py index d74e0d14..6741a538 100644 --- a/pyjamaz/rpc/ws_server_subscriptions.py +++ b/pyjamaz/transport/rpc/ws_server_subscriptions.py @@ -9,11 +9,11 @@ from pyjamaz.constants import MESSAGE_TYPES from pyjamaz.models.block import Block from pyjamaz.models.common import WorkPackageStatus, WorkPackageReportableStatus -from pyjamaz.rpc.rpc import generate_req_id, jsonapi_ws_response, RPCCallException, RPC_ERROR +from pyjamaz.transport.rpc.rpc import generate_req_id, jsonapi_ws_response, RPCCallException, RPC_ERROR from pyjamaz.utils import base64_encode, base64_decode if typing.TYPE_CHECKING: - from pyjamaz.rpc.ws_server import WebSocketServer + from pyjamaz.transport.rpc.ws_server import WebSocketServer class WSubscription(ABC): diff --git a/pyjamaz/transport/types.py b/pyjamaz/transport/types.py index a50d7e2d..5c68ea02 100644 --- a/pyjamaz/transport/types.py +++ b/pyjamaz/transport/types.py @@ -8,9 +8,3 @@ class ProtocolType(Protocol): async def listen(self): """ Starts this protocol, start listening for messages """ - - async def request_blocks(self, direction: int, max_blocks: int, block_bytes:bytes): - """ Starts a Blocks Request, to fetch a range of blocks from a given peer """ - - async def broadcast_block(self, block:Block): - """ Broadcasts a new block to all connected peers """ \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 243ed2c6..e02c7bcd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,3 +18,4 @@ numpy==2.3.5 numba==0.63.0 aioquic==1.3.0 +python-ulid==3.0.0 \ No newline at end of file diff --git a/scripts/init_nodes.sh b/scripts/init_nodes.sh new file mode 100644 index 00000000..249166c2 --- /dev/null +++ b/scripts/init_nodes.sh @@ -0,0 +1,8 @@ +python pyjamaz/cli.py init --db-path ./pyjamaz/data/alice --seed 0x0000000000000000000000000000000000000000000000000000000000000000 --force-overwrite +python pyjamaz/cli.py init --db-path ./pyjamaz/data/bob --seed 0x0100000001000000010000000100000001000000010000000100000001000000 --force-overwrite +python pyjamaz/cli.py init --db-path ./pyjamaz/data/charlie --seed 0x0200000002000000020000000200000002000000020000000200000002000000 --force-overwrite +python pyjamaz/cli.py init --db-path ./pyjamaz/data/dave --seed 0x0300000003000000030000000300000003000000030000000300000003000000 --force-overwrite +python pyjamaz/cli.py init --db-path ./pyjamaz/data/eve --seed 0x0400000004000000040000000400000004000000040000000400000004000000 --force-overwrite +python pyjamaz/cli.py init --db-path ./pyjamaz/data/ferdie --seed 0x0500000005000000050000000500000005000000050000000500000005000000 --force-overwrite + +python pyjamaz/cli.py init --db-path ./pyjamaz/data/karel --seed 0x1111111111111111111111111111111111111111111111111111111111111111 --chainspec dev --force-overwrite \ No newline at end of file