1 | """ |
---|
2 | Ported to Python 3. |
---|
3 | """ |
---|
4 | |
---|
5 | from future.utils import bchr |
---|
6 | |
---|
7 | # system-level upload+download roundtrip test, but using shares created from |
---|
8 | # a previous run. This asserts that the current code is capable of decoding |
---|
9 | # shares from a previous version. |
---|
10 | |
---|
11 | from typing import Any |
---|
12 | |
---|
13 | import os |
---|
14 | from twisted.trial import unittest |
---|
15 | from twisted.internet import defer, reactor |
---|
16 | from allmydata import uri |
---|
17 | from allmydata.storage.server import storage_index_to_dir |
---|
18 | from allmydata.util import base32, fileutil, spans, log, hashutil |
---|
19 | from allmydata.util.consumer import download_to_data, MemoryConsumer |
---|
20 | from allmydata.immutable import upload, layout |
---|
21 | from allmydata.test.no_network import GridTestMixin, NoNetworkServer |
---|
22 | from allmydata.test.common import ShouldFailMixin |
---|
23 | from allmydata.interfaces import NotEnoughSharesError, NoSharesError, \ |
---|
24 | DownloadStopped |
---|
25 | from allmydata.immutable.downloader.common import BadSegmentNumberError, \ |
---|
26 | BadCiphertextHashError, COMPLETE, OVERDUE, DEAD |
---|
27 | from allmydata.immutable.downloader.status import DownloadStatus |
---|
28 | from allmydata.immutable.downloader.fetcher import SegmentFetcher |
---|
29 | from allmydata.codec import CRSDecoder |
---|
30 | from foolscap.eventual import eventually, fireEventually, flushEventualQueue |
---|
31 | |
---|
32 | plaintext = b"This is a moderate-sized file.\n" * 10 |
---|
33 | mutable_plaintext = b"This is a moderate-sized mutable file.\n" * 10 |
---|
34 | |
---|
35 | # this chunk was generated by create_share(), written to disk, then pasted |
---|
36 | # into this file. These shares were created by 1.2.0-r3247, a version that's |
---|
37 | # probably fairly close to 1.3.0 . |
---|
38 | #--------- BEGIN stored_shares.py -------------- |
---|
39 | immutable_uri = b"URI:CHK:g4i6qkk7mlj4vkl5ncg6dwo73i:qcas2ebousfk3q5rkl2ncayeku52kpyse76v5yeel2t2eaa4f6ha:3:10:310" |
---|
40 | immutable_shares = { |
---|
41 | 0: { # client[0] |
---|
42 | 0: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmksehmgmlmmeqkbxbljh5qnfq36b7h5ukgqccmy3665khphcxihkce7jukeuegdxtn26p353ork6qihitbshwucpopzvdnpkflg6vbvko7ohcmxjywpdkvjmuzq6hysxfl74mamn224nrsyl7czmvtwtss6kkzljridkffeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7y5y3kjcfritduzdk5rvwqs4lwzvb7fgvljgozbbtamhoriuzaeruaaqt2fbbxr5yv4vqeabkjqow6sd73dfqab3qban3htx6rn2y6mujdwaacbpvbyim4ewanv2vku44tunk7vdjkty2wkfm3jg67pqmm2newyib4aafazigyt6kxmirnlio5sdvbkvh43rwpctm6coigl64chn6z7w45rcaaccvmfgplu4kz5erphnx3xhzclypawi2j5zsvewmn4s2wbba4k2ktaab45y3kjcfritduzdk5rvwqs4lwzvb7fgvljgozbbtamhoriuzaeruaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabj5uiln36za2n4oyier7k5e4sx6newmmflfqhj7xffy32p5iohlyf33bdx5dafkfwr7rxwxjcsg3ljflkaae537llwnnykgf36h52dojfplbwi"), |
---|
43 | 5: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmsdsvwbnfx2rnh7dusqniqomsdeetuafps6cawyb4pzxpkzal7w5ufaknxfnqw2qywv4c3a2zlumb2x2rx5osbxd3kqmebjndqf7zihbtagqczgwrka5rnywtsaeyijyh26okua2u7loep2nzo5etirjrxmp3yxpb4pheusaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zs3zcg7igd2xoa4eu3lffqginpmoxrshqe6n3hzpocihgeu4vvymaadjz54nelgyi47767pkbsjwdjgsv7uyd5ntrztw6juavj7sd7wx7aaacx7wxlycyjniwxvby4ar546ncb4d3jnbhssnq4n4l4xeajurmn5diabgxwi6i5d2ysny3vavrm3a5lsuvng5mhbzk7axesyeddzw6uzmnluaakglpei35aypk5ydqstnmuwazbv5r26gi6atzxm7f5yja4ystswxbqaakbsqnrh4voyrc2wq53ehkcvkpzxdm6fgz4e4qmx5yeo35t7nz3ceaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabj5uiln36za2n4oyier7k5e4sx6newmmflfqhj7xffy32p5iohlyf33bdx5dafkfwr7rxwxjcsg3ljflkaae537llwnnykgf36h52dojfplbwi"), |
---|
44 | }, |
---|
45 | 1: { # client[1] |
---|
46 | 2: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmj7um4zfgqo35m62ln6has6xz43klzjphj5eg46mb5x2jzgr6x6zb4voveo5uef53xbjbktr5rlupomy7x5b34amqeeg4r6obt6kpo2x4s3m3cwoo54oijyqfms3n3fethykhtglc47r4ci7ugqgz5d5fap3xzyhm4ehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zqkzg32wa74epeppqwneujs6tjptlm4qw75hoafobsoif3ok5odkaarmcwjw6vqh7bdzd34ftjfcmxu2l423hefx7j3qblqmtsbo3sxlq2qaewyffwgzojfi4uj2praj5azehnr4fhan5kdyewhtfncrqzoe42ijeaaikvquz5otrlhusf45w7o47ejpb4czdjhxgkuszrxslkyeedrljkmaabigkbwe7sv3celk2dxmq5ikvj7g4ntyu3hqtsbs7xar3pwp5xhmiqaa6k7uub7uqlamlqi2oduautemch242scu7cfor6kedxs6mm3uwjsmaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdp37hh2k4ys4d7qusb5e3dakjntythtcwcwfok7e52pu64zn4wrwbtlkzxzntwuwemi6e6mek5n4i7h3bw7nkat2zmqieftinxgzl2jfplbwi"), |
---|
47 | 7: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaaznhsh2frhzxbutelvddtbuf3tfilhcj2zi3cxjyzy7pg7ewamazcblv76mvey54fxmch64chqfi24jmondc4uzitby3wjeui4nfp7kv6ufo67exptkvwk7cnbouvjiapyqzrps4r6ise4jhlr7mtp2tlizb5hyaqm3fhsvrmqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl72g6h2oewtfcwgupjbjnh4k5k6d3k2fpi2q6nyidh3yo5ui6cslreaajms7f3pcsywhjbgrybzp64jzlsyjqbu7h4hvdlwf77ar6l63imdeqaaudfa3cpzk5rcfvnb3wioufku7togz4kntyjzazp3qi5x3h63tweiaagtt3y2iwnqrz77566udetmgsnfl7jqh23hdthn4tibkt7eh7np6aaakvpbzjdki64qaigkdj2bven3uigxbpurpwtrkjs4b6habv2ls7zqaac2g6h2oewtfcwgupjbjnh4k5k6d3k2fpi2q6nyidh3yo5ui6cslreaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabdp37hh2k4ys4d7qusb5e3dakjntythtcwcwfok7e52pu64zn4wrwbtlkzxzntwuwemi6e6mek5n4i7h3bw7nkat2zmqieftinxgzl2jfplbwi"), |
---|
48 | }, |
---|
49 | 2: { # client[2] |
---|
50 | 1: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmkrwrt6figauxkgqyk3nggp5eeoeq5htt7tke4gfqj2u5roieslao4fldcwlq4btzk4brhkaerqiih6mhudotttrb6xzmvnqgg33fjcqeuw6teb3gml2pmhsezisa5svnzlvqnbaz6kzdmhisbwgu6ocexf2ge2rvc67gneqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl72piueg6hxcxswaqafjgb232ip7mmwaahoaebxm6o72fxldzsreoyaaif6uhbbtqsybwxkvkttsorvl6unfkpdkzivtne3356brtjus3bahqaee6riin4pofpfmbaaksmdvxuq76yzmaao4aidoz457ulowhtfci5qaafazigyt6kxmirnlio5sdvbkvh43rwpctm6coigl64chn6z7w45rcaaccvmfgplu4kz5erphnx3xhzclypawi2j5zsvewmn4s2wbba4k2ktaab45y3kjcfritduzdk5rvwqs4lwzvb7fgvljgozbbtamhoriuzaeruaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaugotrr7enihxy2b2nwodhxabihaf3ewc2hmcdjsqx5hi4h3rn7gnvpt3lzzo5qgbnlp4dybwr7dn7vu5hsiyo5pedlqcasb7csiuojfplbwi"), |
---|
51 | 6: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazm34cgyp37ou5ohrofmk6bf5gcppxeb2njwmiwasn3uh4ykeocvq4vydsw36ksh63fcil3o257zupffrruiuqlwjvbdcdjiuqrojiromunzxxc34io7zlfafprzlvmztph4qsp67ozxmwvivqwtvu6ckr7pffsikgi2supviqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zlyoki2shxeacbsq2oqnjdo5cbvyl5el5u4ksmxapryanos4x6maaajms7f3pcsywhjbgrybzp64jzlsyjqbu7h4hvdlwf77ar6l63imdeqaaudfa3cpzk5rcfvnb3wioufku7togz4kntyjzazp3qi5x3h63tweiaagtt3y2iwnqrz77566udetmgsnfl7jqh23hdthn4tibkt7eh7np6aaakvpbzjdki64qaigkdj2bven3uigxbpurpwtrkjs4b6habv2ls7zqaac2g6h2oewtfcwgupjbjnh4k5k6d3k2fpi2q6nyidh3yo5ui6cslreaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaugotrr7enihxy2b2nwodhxabihaf3ewc2hmcdjsqx5hi4h3rn7gnvpt3lzzo5qgbnlp4dybwr7dn7vu5hsiyo5pedlqcasb7csiuojfplbwi"), |
---|
52 | }, |
---|
53 | 3: { # client[3] |
---|
54 | 4: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaaznjqn7ehmj6f4p3fjyliuvwnfothumsfhs7ienw4uln6joaxopqlmcy5daa4njrkgj7nqm6tpnmz2dci2b356pljv4zjj5ayzfihi4g26qdei7kjtegjuv4d3k3t4orpufnft3edbondkpj5etjczwhyulukzuy5socyivdfqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7zpmr4r2hvre3rxkblczwb2xfjk2n2yodsv6bojfqightn5jsy2xiaatl3epeor5mjg4n2qkywnqovzkkwtowdq4vpqlsjmcbr43pkmwgv2aacx7wxlycyjniwxvby4ar546ncb4d3jnbhssnq4n4l4xeajurmn5diaagtt3y2iwnqrz77566udetmgsnfl7jqh23hdthn4tibkt7eh7np6aaakglpei35aypk5ydqstnmuwazbv5r26gi6atzxm7f5yja4ystswxbqaakbsqnrh4voyrc2wq53ehkcvkpzxdm6fgz4e4qmx5yeo35t7nz3ceaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacifoqlus3puiqkekp6g6fdecjcx2bak27angodamzoxugovlhtcj5xbly7teqwmf73fqk3clyfvs6hdauq5qnqahlxlmp2vrmnneedgjfplbwi"), |
---|
55 | 9: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazn2tz3qt62bgsdnvksvdegsylb2kbltouheryflpho7hugme7svk7so2v7hmcgc43tcyugybuqzgifvkllikfiiezvml7ilolb7ivwvrv4d4t2gbywa44ibqwogmjtffta4b2sfwqebfg7pptergeqm5wo3tndtf7p3vftabqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl7y3m26swfhsb66ze4cmyhohaksid7fyljgkhag32ibc7vx2yj4j5saayg3gxuvrj4qpxwjhatgb3rycusa7zoc2jsrybw6saix5n6wcpcpmqaamxjsc6bwv4w4or2oylltmsbfbobvmenj3sa6lnq6iy4tugsnv72eaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaadirzs2idl54toffh4a2hehvg2e3zoed4dr6pcdpuqpnz2knte7gqqac6kfatp33ianoqvg6mdd4vaxa27lo6vpugbcvanhskaqq2kewn6kwaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacifoqlus3puiqkekp6g6fdecjcx2bak27angodamzoxugovlhtcj5xbly7teqwmf73fqk3clyfvs6hdauq5qnqahlxlmp2vrmnneedgjfplbwi"), |
---|
56 | }, |
---|
57 | 4: { # client[4] |
---|
58 | 3: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaazmbduh5nwvcvpgrihhnjxacz2jvzu3prrdqewo3vmxkhu5yd3fa3eil56fyh5l7ojimghwbf2o6ri7cmppr34qflr5o4w6s5fekxhdt3qvlgsw5yp5wrmjjffhph5czd5kzoo7yyg5x3wgxxzdvwtuom2c5olao62ep77b7wqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl73mcs3dmxesuoke5hyqe6qmsdwy6ctqg6vb4cldzswriymxconeesaarmcwjw6vqh7bdzd34ftjfcmxu2l423hefx7j3qblqmtsbo3sxlq2qaaudfa3cpzk5rcfvnb3wioufku7togz4kntyjzazp3qi5x3h63tweiaaikvquz5otrlhusf45w7o47ejpb4czdjhxgkuszrxslkyeedrljkmaajnqklmns4skrzitu7cat2bsio3dykoa32uhqjmpgk2fdbs4jzuqsiaa6k7uub7uqlamlqi2oduautemch242scu7cfor6kedxs6mm3uwjsmaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadusyxmwhtnfdeewwgxd25fwixycfdcy46ifqv4dhga23fko6dbl4ywo2d27n3zh3wd6zumhupvmtgspqrh6t7wbsghruzqd3imbo2tojfplbwi"), |
---|
59 | 8: base32.a2b(b"aaaaaaiaaacyeaaaaaaqaaaaaeaaaadiaaaaa2aaaaaciaaaacgaaaaavqaaaagmaaaab3aaaaaznjzqcxwyhgwlcpzvfb2berhoyw47h72gkzofwgksryqd4r6xlyougvyg4p3wkz7u37zllskeswuuh4w2rylbxecomnmqfv7n5ex3thjzq7ykr7gjkvq3kmrlhmxu3wnsr4ipsdn546btavjzc6yppoii2mxgnnk4qbxqrltaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaactwxn7tsxj2nh6skwbghycguqfj7xrpegeporex5ebctynbgbl72kfatp33ianoqvg6mdd4vaxa27lo6vpugbcvanhskaqq2kewn6kwaayg3gxuvrj4qpxwjhatgb3rycusa7zoc2jsrybw6saix5n6wcpcpmqaamxjsc6bwv4w4or2oylltmsbfbobvmenj3sa6lnq6iy4tugsnv72eaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaadirzs2idl54toffh4a2hehvg2e3zoed4dr6pcdpuqpnz2knte7gqqac6kfatp33ianoqvg6mdd4vaxa27lo6vpugbcvanhskaqq2kewn6kwaaaae4gg33emvrv63tbnvstumz2mnzhglddn5sgky27obqxeylnom5dqortgezc2mzngeycyy3spfyhi5dfpb2f62dbonudumzshkl7fjw5sp7x3yw4sdhze6qf7zgsjocpqtwl2gj5o6vufvixto3u2lddoj4xa5dumv4hix3sn5xxix3imfzwqortgi5fhno37hfotu2p5evmcmpqenjakt7pc6imi65cjp2icfhq2cmcx7rmnzswkzdfmrpxg2dbojsxgorrhizsy3tvnvpxgzlhnvsw45dthiytumjmonswo3lfnz2f643jpjstumz2gmyteldtnbqxezk7ojxw65c7nbqxg2b2gmzdubzmius26hljzu4j7gq5hdshwueqcfjc2bmveiyqbdxgyejetzovfrzws6tfhiztumzrgawhiyljnrpwg33emvrv64dbojqw24z2ha5dgmjsfuzs2mjqfr2g65dbnrpxg2dbojsxgorshiytalaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadusyxmwhtnfdeewwgxd25fwixycfdcy46ifqv4dhga23fko6dbl4ywo2d27n3zh3wd6zumhupvmtgspqrh6t7wbsghruzqd3imbo2tojfplbwi"), |
---|
60 | }, |
---|
61 | } |
---|
62 | |
---|
63 | mutable_uri = b"URI:SSK:vfvcbdfbszyrsaxchgevhmmlii:euw4iw7bbnkrrwpzuburbhppuxhc3gwxv26f6imekhz7zyw2ojnq" |
---|
64 | mutable_shares = { |
---|
65 | 0: { # client[0] |
---|
66 | 2: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohgreckgxome2uhcps464pzydv5wsywald7wthurw2dp6qxtkeb5vtswoeshuyno24v5oble7xb4j6ij7wwqriaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3wrm2mwdv3syv4r34b5mklbtjuv5i5bzcuiwgfnl4wtpombwn7l7ugdvv2xut7hwbttcjfsacuhc7ipf43gvrgrt5vj7hau52uenoywreckgxome2uhcps464pzydv5wsywaldqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaaohafr65kctby6wa34bjpnviviiwmwq5mft3yho4tmslaarpcg6biaajlxuwwafut5a6dsr7lq5fkmiik7icppic5ffjjmqaud4y746q2rzd42k42oitzukawdl2fupkoqcztfu7qf2flp55xh4lm6rzpdbb7gtnx4kaffym36rboalf2tbmatt46ra6igvjnvwmig6ivf6gqrhcietf373xrbm3bpeecz7luv7kv76i7pwa5xtubga37vnlu6hspejpsenxiptd23ipri7u5w7lz67mdjfrpahtp5j46obg4ct7c5lelfskzqw5hq7x7kd7pbcgq3gjbv53amzxjelwgxpf6ni74zb6aixhjjllivkthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"), |
---|
67 | 7: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohgreckgxome2uhcps464pzydv5wsywald7wthurw2dp6qxtkeb5vtswoeshuyno24v5oble7xb4j6ij7wwqriaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3wrm2mwdv3syv4r34b5mklbtjuv5i5bzcuiwgfnl4wtpombwn7l7ugdvv2xut7hwbttcjfsacuhc7ipf43gvrgrt5vj7hau52uenoywreckgxome2uhcps464pzydv5wsywaldqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaaszc7rkciv6rhwt5gbgnl5u54ihnqrfyuh7s54r2444mrhcwgizieaak4ap2xhvuz664fw3kayv7z5vawqs7skj6frzp3ihmk7js3tr7cwpnbfwoefuyn6bqkj5kssx3rvvffqgd3mhb7pbtegk6qfvsopvzmsiftabaykw3qitiqcv2wwfvdud5lkbjigatrf4ndeejsij5ab3eyaqqgxfiyxtv674qwltgynickeznu5el6uhs2k75hq2rsxhco2kmxw4didbdjodmjf2nrne63du76fd6laa7ng7zq4i7bx2xtohfrgwlxls6h7ibfsbybdz46sow3tn4vao3ulciz75kfbb62jrz3omvnihr2jwthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"), |
---|
68 | }, |
---|
69 | 1: { # client[1] |
---|
70 | 3: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohm5tnwcmfsfmep4exoamss5lqyleq2ehahoduym5vgk37pmxx2xekzrtlzfvhapzb2fe3quv6tv3atr3g6ykqaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvx5mk74p2on26ax4rlp5jcoto5jkz3ndmgbmurhez4a5rbuyr55acbwlgbndlebsdyvlt4ttog767zqpoq3n2a4pra5va2o5zvbttlh45tnwcmfsfmep4exoamss5lqyleq2ehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaaohafr65kctby6wa34bjpnviviiwmwq5mft3yho4tmslaarpcg6biaaixzuvzu4rhtiubmgxuli6u5aftglj7alukw733opywz5ds6gcd6nf32llac2j6qpbzi7vyosvgeefpubhxubossuuwiakb6mp6pini4rja473klkmi52lzfwofja7bb6pixgcxkwdaerc2irfpnrqwh5o2remu3iv3dtib75ku63cb6xzj4h53nmsguanjpganh3ow5yzovjcsezsj2cunyvlpva63zx5sudxe2zrtcu5zoty2tjzzlhodaz6rxe62ehbiktd4pmaodaz6ajsrohw7tdga2dpaftzbhadsolylgwgtbymenwthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"), |
---|
71 | 8: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohm5tnwcmfsfmep4exoamss5lqyleq2ehahoduym5vgk37pmxx2xekzrtlzfvhapzb2fe3quv6tv3atr3g6ykqaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvx5mk74p2on26ax4rlp5jcoto5jkz3ndmgbmurhez4a5rbuyr55acbwlgbndlebsdyvlt4ttog767zqpoq3n2a4pra5va2o5zvbttlh45tnwcmfsfmep4exoamss5lqyleq2ehaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaabduzspufh6gomrp7sycuerhgl7ah3x3mpc6watmzlp6y23afmlxcaabui4znebv66jxcst6andsd2tncn4xcb6by7hrbx2ihw45fgzsptiiaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaamprqe6ozjrouoeltzhezhntop7wb6bbnnr3ak6x3ihvsjlz77gffkdet4sc63bxykwaikdyxwoehbrggxdu6qcwquzsnaltcgn52nyy4ypqbthfg4txtnznap6dktqtgtmtu7icooojppbwyi5c22uehbveptbuhbi7q3d4wuvsrptnd6wrhxwtlkxe4kurp4fey52p2v6urgephzxmaqfhm7pq3wxbi2uj5ourg65xnhbo4lrp7nzrdmk3svespmmitccvtwom6wtqefpp73j67zybiu4wrjjqt7vhip4ipuaezkmdy7feothks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"), |
---|
72 | }, |
---|
73 | 2: { # client[2] |
---|
74 | 4: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohelfyqrvy7pzjh3tqx73xsfkpi3so4qjghlywdkwuioyjvbtgekiulaes4myuxydi2sudi2fkg2q5nkjrt3zaaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynujj2kh34jfiungka3deihevw7p3mzhj7uobc3qnbfxqp3xfazrsicvtz3enqkn4xxlu5xvxjj2rtlv6j3w3kmpzn2jbrnuoafq2aacoulfyqrvy7pzjh3tqx73xsfkpi3so4qjgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaavmjy6g336aewy42vw5rusytyi7vzs6y22c5jhxyt5w6gthcbjp4zaakhlvz26psskxjisz27qlpzw4annhegunhnvlyr35ijotdizegjf4lgx3o4dt3d6d4bjqexz2eu3dprjlmuvlkbfcpmkq2ceydywqqcqdhmdl2nm5ku6z6gnss2bsbn7ycab2ggktr3bjlzaeo5pb4meolrckviwiddsikieo4wyatlxtybmzkoh3fb2vxc34xb47ty2cyi55xjan6m4bbie7muzrzmjmzviwlotk6icove7ydpag6dlrjwu4svgs3y2ln5r463dmflqs3p4aa7dldhjb5kfpxq63tgquunkucsfvlkaiiisgthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"), |
---|
75 | 9: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohelfyqrvy7pzjh3tqx73xsfkpi3so4qjghlywdkwuioyjvbtgekiulaes4myuxydi2sudi2fkg2q5nkjrt3zaaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynujj2kh34jfiungka3deihevw7p3mzhj7uobc3qnbfxqp3xfazrsicvtz3enqkn4xxlu5xvxjj2rtlv6j3w3kmpzn2jbrnuoafq2aacoulfyqrvy7pzjh3tqx73xsfkpi3so4qjgaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaabduzspufh6gomrp7sycuerhgl7ah3x3mpc6watmzlp6y23afmlxcaabui4znebv66jxcst6andsd2tncn4xcb6by7hrbx2ihw45fgzsptiiaaybvqu3gmlomi3dnf2tum3hoseavpesyia2i2wqgwbmbtrgmotu6oaalugjhzef5wdpqvmaquhrpm4iodcmnohj5afnbjte2axgem33u3rr7yycphmuyxkhcfz4tsmtwzxh73a7aqwwy5qfpl5ud2zev477tcsviylwmlv6fgp54rk4iwputjkcgegczq6uynbvebu67jf6f2foocphznw7jrdsvphppguypjwmkkhugm6yjnrjka2ycvxsyh5xohn3fvbbhl4tvhedbaix3zlwxeayabnldp3oqnkjger7yrxh44wuv3adb76jh3nl6h45t4ixj77himst5plmpdtexyoozpxzjmedge5leynxhziothks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"), |
---|
76 | }, |
---|
77 | 3: { # client[3] |
---|
78 | 1: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohar2c5jzdcrekne6myzpxl2z65d6ufdjuuyhabg2j57ecmy23jyflcp7djzupj4tfr345bkg7cmwxmpmn3h4iaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3sjzjwrfjn4cwfspkueq47j6ej2uodmjsjexyray7dn6ut4nnuftdhhgxo3t3a5eoipsdy5evdihyeigny3c4adtpveplcwt76m7naar2c5jzdcrekne6myzpxl2z65d6ufdjuqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaarzybn64ru5rss7tmi4ttv26q66ebdvvrtyd3s5t7dmqku3uoefroaahxhmt46bsa3cpmjfwjyw3zijhhbqh3j2dbc42jaqj6wvmxoz7pecirykndmb6dylde5utzkpucky5pk3x4u6dphkq2ycmfuyvpg5lsudusosyofwfnokbe7qmld2xwaxah3qkywarndsfvp3rybq2y7q42silj5cnlbdxnabv2zhhix3h5o5kz2ttqzm34clnbo527obrxvqlxz3sofwcmz2kqs4c3ypj6o4ny4hkh6qu7ljs7xiygzmoojhnaxc6wjbnvnsu2socztfaegy6ft22tgtdudtok4z755vgj3etwmje73af2f2thks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"), |
---|
79 | 6: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohar2c5jzdcrekne6myzpxl2z65d6ufdjuuyhabg2j57ecmy23jyflcp7djzupj4tfr345bkg7cmwxmpmn3h4iaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynu3sjzjwrfjn4cwfspkueq47j6ej2uodmjsjexyray7dn6ut4nnuftdhhgxo3t3a5eoipsdy5evdihyeigny3c4adtpveplcwt76m7naar2c5jzdcrekne6myzpxl2z65d6ufdjuqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaaszc7rkciv6rhwt5gbgnl5u54ihnqrfyuh7s54r2444mrhcwgizieaalkclm4iljq34daut2vffpxdlkklamhwyod66dgimv5alle47lszewah5lt22m7poc3nvamk7462qlijpzfe7cy4x5udwfpuznzy7rlhx7ev5hmvxi5m3nctyofw2axz6a4fttdxoefezaqu7wur2rtcmxx5wxmpdkfflvzvawzr2oecq7yriklbc2nfyk4ezeulmdaktctlwcoz26jt3yx5gg2ez6jnhblc5swn7qbl6t3ebm2fmworvtrpxyqhegsly6xtpbh2yfdu6ww52ypka6cc4crgov33cdnbxyekdmjck2h55ni4othks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"), |
---|
80 | }, |
---|
81 | 4: { # client[4] |
---|
82 | 0: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohanguihdeqshi3vbil354mnoip7yzj3rpsvjbydjlngiqocl2s6dja4dqjzuaghaekxoithualnjp6artv6laaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvzguwqjavmynllmjm66qaqz4uh4dinujrxcaafvp5vvzrgueu3fxwkppvopapdw3p4hjezva23vxif5rzgacysmyo7tr4tjd44nnqpsanguihdeqshi3vbil354mnoip7yzj3rpqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaabdm4cpjolak4m47telnokjaxwodj7ont7n7vffnmhkzp3lyshkh3qaarzybn64ru5rss7tmi4ttv26q66ebdvvrtyd3s5t7dmqku3uoefroaaibdqu2gyd4hqwgj3jhsu7ievr26vxpzj4g6ovbvqeyljrk6n2xfidtwj6pazanrhwes3e4ln4uettqyd5u5bqroneqie7lkwlxm7xsbg4zhnlc2fybonhlpcatwlgdvk3jpn7sge4qnod2ufxgxc7rphbnunb52xrgmdgpojqhyfajxealxwdddlhhbttphrgv5zrub5mggbcec3honrtuuv3epex3s5yvkt2zmsaxfeu34psjwjltm4ys5qa72ryrmgjtmtu3i34jfmachhmgul2j2sddwydgvtpqnatglb3ejlhukxp3isthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"), |
---|
83 | 5: base32.a2b(b"krqwq33febwxk5dbmjwgkiddn5xhiyljnzsxeidwgefhkckeaohanguihdeqshi3vbil354mnoip7yzj3rpsvjbydjlngiqocl2s6dja4dqjzuaghaekxoithualnjp6artv6laaaaaaaaaabb5aaaaaaaaaacsoaaaaaakjl2ynvzguwqjavmynllmjm66qaqz4uh4dinujrxcaafvp5vvzrgueu3fxwkppvopapdw3p4hjezva23vxif5rzgacysmyo7tr4tjd44nnqpsanguihdeqshi3vbil354mnoip7yzj3rpqaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaarybcjqw7lbehfrbu7pwx26vvv3mbjprnqup7q7wxmdsoyiqaqzgbtv6cplrrgpzbnptsoqz7imnauamfaaaaaaaaaaamgaaaaaaaaaaaymaaaaghqaaacr4aaaayxaaaagnyaaaaaaaaaao4qaaaaaaaaacd2gcbacibqbudaskugjcdpodibaeaqkaadqiaq2abqqiaqqaucaeaqbvkghg3s5ivqiq4uiajdzagl7iqhz2uxwj6aqk47oscyqxyljmxkapldxhxigum2ejxflnps3yrxwwehop2zairilrouid5s6wxgnoqg2vq7rx77icxfnx7mq65niuknra3tezhpndwo7pdxtvtci645p4umyhdh5gp3kbdpypphvouaql662r6ufigp4wwm6emrsavlontn4wttg6lv7bcmq6ojw5utpvz3agoenovrkndncjzxog7sp2w7l6jkmzgfxd2asxos5khkjbxbuhgkd6j5yqlzsmk3kq67engtlgyd7hxk7nedw73bq2bs4353wtler23poucntgve22acfxdbyj2f6q2saj2agu2ptfk364d3zayddffxkcah4olnkczjonselwwrvdcu3vch3licaeirogosgsui3y4ovcyzleurbiunp7fsfk2fgmiek7b3jogvrhj4snvkpqjfh2w2lqnkvqvuoojmgrn6sll354mpomajbtlsv6fuguzgsxsm3l2ehxdxfdv6kcoyogaa5raetooahunf4ltvfdb4d7mwgpj4pg7tmcw55ku5vgx7tjqkdkuyq2uvhavkbsbujsrcfzve5ekuhftxm7nmtomibrblbwyxcr5mcy6qqwx66lrhejmgewrig74nzpriualhw4g22qaw423qeezqn6irea3vlgc3foz4egf6irincownoq7utv643vmtoueebigwrl6nehbos3ipsdx44tmucpvyui2jzgfulb5mrrcjuycmuzfigu6tf25lbysqn7n7smhqniddgctjt573rtd6o63wiaactacm7dw7giohzcgwe4okbijnmzlacetmfjjbasrd6whexjmwkaiaaazuum3xriq54h5v6afcrrl3kkbd46oizwulc5fbslmblxfc3ldyyqaavmjy6g336aewy42vw5rusytyi7vzs6y22c5jhxyt5w6gthcbjp4zaajwnpw5yhhwh4hyctajptujjwg7cswzjkwucke6yvbuejqhrnbafadv245phzjfluujm5pyfx43oagwtsdkgtw2v4i56uexjrumsdes6go7556an26wmzpbskyrsx4qbzqcedilovhlkrlnhvsfr4mjwkw62mkf4kde7jgesu4ztbzc7xmuobydnxk5hdyyly6n7socvrsqw6z56v6osxr2vgxpz6jor7ciyclkungeaayume5hdrm6cbnvwgua4gc2fcpixfdbkiijnmlicribyoinnpu6zdce4mdfqyl4qzup3kkk5qju2wthks6df52kvobtcnscytmjrrfbekvwmhtbcke2cgcyaj2cra7xmnd4bw2xe2qki5kycopo45ekfyxwzsmxuyxvjzqklnqjwm3j3gwcm75ftnrsvbj33w6eyr4dbz2tewum7vfsyfbb3ojw5ujtn22jxpr4nkmkqup6z7ukpp4cdxwyge2psc5suaxaltmp23gbawoo3qjeo44hgwgtkge2oowox3fpxwxkckaqgrxilfeyxmjp4cwf2rhpkbwtveqkukchv3u5rfkykwfj5zhleu3obsif6ldfclaef32wjpe5d6ddh2grdx2yt6tuhw53t6zuuumlw6t6i3e2ev7nh36e4shwbn3ew2bbahn6imgb5sismfttf5cdlr5kw6wvjoaqiaiz2onxecfx735dvon7epthnklq67tnqj4fvcwechbvmnkpiwd5fd36dirpshc7i7zj3rcr5y3kzps5nfnfnik27gdgemfn27iblcjh5bpkio6sr375bmxbh6fshbo7cvjzsdsirsafnbjzgl6ycqczwbacj5sxwgrzl6qbdhfbzev5fzutznzbasejqdjm3qxsdcuqvqau3kih2anr2itgmr44wmwtsk6bd42m2j436ptslaugmbbvtbzsukeqytkse7niovlilyfssn3ipzkqtclmetqrxxn7h56xn2ju7pjnuamd6ijfawn2jpjsrmnawaozeniosvhgovftoj24dl77ytdkxdl7ogappnlgkqsjyy43urtnj6tqf2psfptkbzyx4nu3rzgsqqi5ybx3pu6cvt6de67xutdz566wrkp2ymy5n7tqchmw77ss532noqcbfxv6quum6jmeed3exasdapvid6bilwzm5dcnutkcxktmsdryqopw5ntws3tnbd7um27clmxkgl2uinwzvv4tmo4axbj5zmgfd6sy2fiw6efdwjcyj4awdx3peuxcyh3ccee63w2nqaltierdrevl3f3hnjsrdrl4aosd23szhhaimhg2mjuocottcdsraoczh3waoyxx2skunaphe6w5gutu2z7cag3cx4pgsspfmspphuunzx357x6l36hj3tdys727rhawfwc4wc4ytgts4nrxlxl3xxzffunlhjhzj5guxljwxfrxwjfsg5c67pg3js7gvfqmpson6rjgiuwbsklranwhauq74lbesavftdzf7y3x5zwbi4uu6q2vqimbkttm7k6ycttsgknej2ylkwdxgtut7wecpepnb527pblj3vuzldjt3whsmstax536plulalxtxmvj6vvg4phofyaidhxhhkl4dfb6oabp3fi55jt77pw3jl55pwbsimjpdanuenll2xxctr6swaimuaqk4wvqa6rbgow3onr74v4alkuukc2tlmorvsjpgaazpun6pbfyorazzarhc2r7fjt55pmosowrqcpdwl2q34hcco2f3icmpktchxdvtpmitufnplqaifbtlktkpo7b22244n6dkmxtgcnxtixsit57uhh7rc5rqezjz7pfd7ojhrui5bcdzb7bo2nbo6o24lpwbg4bmqgbqpbwclq6kglgxefryxlkqydillki3545vcrelfw6reszml6emuyjscx377on2qpq26j5jrh5xmbwmpcyq6sewanlbmwwk2vqhq5zunbcyd6h5z3ms3bgfn7lflvev5vwmjnv5nzbgrmpamy453zuvy6xc6jp7tqgpmrlxup7suptejbacm6rdurdhcaori6i25wylgaikfov4dfgeswxdeerogy2m5tbzsdlr7pfhchd4wnokuipfwjzejxiruj5cljm66hvn47j3eseys3nsi6xdh566jgap5s5e7ytdkkhh5lsuv47oose4luozz427dzk577jccjg3n7b4myd565edmsywol3hgh2i54lcya6saaaaaaa"), |
---|
84 | }, |
---|
85 | } |
---|
86 | #--------- END stored_shares.py ---------------- |
---|
87 | |
---|
88 | class _Base(GridTestMixin, ShouldFailMixin): |
---|
89 | |
---|
90 | def create_shares(self, ignored=None): |
---|
91 | u = upload.Data(plaintext, None) |
---|
92 | d = self.c0.upload(u) |
---|
93 | f = open("stored_shares.py", "w") |
---|
94 | def _created_immutable(ur): |
---|
95 | # write the generated shares and URI to a file, which can then be |
---|
96 | # incorporated into this one next time. |
---|
97 | f.write('immutable_uri = b"%s"\n' % ur.get_uri()) |
---|
98 | f.write('immutable_shares = {\n') |
---|
99 | si = uri.from_string(ur.get_uri()).get_storage_index() |
---|
100 | si_dir = storage_index_to_dir(si) |
---|
101 | for (i,ss,ssdir) in self.iterate_servers(): |
---|
102 | sharedir = os.path.join(ssdir, "shares", si_dir) |
---|
103 | shares = {} |
---|
104 | for fn in os.listdir(sharedir): |
---|
105 | shnum = int(fn) |
---|
106 | sharedata = open(os.path.join(sharedir, fn), "rb").read() |
---|
107 | shares[shnum] = sharedata |
---|
108 | fileutil.rm_dir(sharedir) |
---|
109 | if shares: |
---|
110 | f.write(' %d: { # client[%d]\n' % (i, i)) |
---|
111 | for shnum in sorted(shares.keys()): |
---|
112 | f.write(' %d: base32.a2b(b"%s"),\n' % |
---|
113 | (shnum, base32.b2a(shares[shnum]))) |
---|
114 | f.write(' },\n') |
---|
115 | f.write('}\n') |
---|
116 | f.write('\n') |
---|
117 | |
---|
118 | d.addCallback(_created_immutable) |
---|
119 | |
---|
120 | d.addCallback(lambda ignored: |
---|
121 | self.c0.create_mutable_file(mutable_plaintext)) |
---|
122 | def _created_mutable(n): |
---|
123 | f.write('mutable_uri = b"%s"\n' % n.get_uri()) |
---|
124 | f.write('mutable_shares = {\n') |
---|
125 | si = uri.from_string(n.get_uri()).get_storage_index() |
---|
126 | si_dir = storage_index_to_dir(si) |
---|
127 | for (i,ss,ssdir) in self.iterate_servers(): |
---|
128 | sharedir = os.path.join(ssdir, "shares", si_dir) |
---|
129 | shares = {} |
---|
130 | for fn in os.listdir(sharedir): |
---|
131 | shnum = int(fn) |
---|
132 | sharedata = open(os.path.join(sharedir, fn), "rb").read() |
---|
133 | shares[shnum] = sharedata |
---|
134 | fileutil.rm_dir(sharedir) |
---|
135 | if shares: |
---|
136 | f.write(' %d: { # client[%d]\n' % (i, i)) |
---|
137 | for shnum in sorted(shares.keys()): |
---|
138 | f.write(' %d: base32.a2b(b"%s"),\n' % |
---|
139 | (shnum, base32.b2a(shares[shnum]))) |
---|
140 | f.write(' },\n') |
---|
141 | f.write('}\n') |
---|
142 | |
---|
143 | f.close() |
---|
144 | d.addCallback(_created_mutable) |
---|
145 | |
---|
146 | def _done(ignored): |
---|
147 | f.close() |
---|
148 | d.addCallback(_done) |
---|
149 | |
---|
150 | return d |
---|
151 | |
---|
152 | def load_shares(self, ignored=None): |
---|
153 | # this uses the data generated by create_shares() to populate the |
---|
154 | # storage servers with pre-generated shares |
---|
155 | si = uri.from_string(immutable_uri).get_storage_index() |
---|
156 | si_dir = storage_index_to_dir(si) |
---|
157 | for i in immutable_shares: |
---|
158 | shares = immutable_shares[i] |
---|
159 | for shnum in shares: |
---|
160 | dn = os.path.join(self.get_serverdir(i), "shares", si_dir) |
---|
161 | fileutil.make_dirs(dn) |
---|
162 | fn = os.path.join(dn, str(shnum)) |
---|
163 | f = open(fn, "wb") |
---|
164 | f.write(shares[shnum]) |
---|
165 | f.close() |
---|
166 | |
---|
167 | si = uri.from_string(mutable_uri).get_storage_index() |
---|
168 | si_dir = storage_index_to_dir(si) |
---|
169 | for i in mutable_shares: |
---|
170 | shares = mutable_shares[i] |
---|
171 | for shnum in shares: |
---|
172 | dn = os.path.join(self.get_serverdir(i), "shares", si_dir) |
---|
173 | fileutil.make_dirs(dn) |
---|
174 | fn = os.path.join(dn, str(shnum)) |
---|
175 | f = open(fn, "wb") |
---|
176 | f.write(shares[shnum]) |
---|
177 | f.close() |
---|
178 | |
---|
179 | def download_immutable(self, ignored=None): |
---|
180 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
181 | d = download_to_data(n) |
---|
182 | def _got_data(data): |
---|
183 | self.failUnlessEqual(data, plaintext) |
---|
184 | d.addCallback(_got_data) |
---|
185 | # make sure we can use the same node twice |
---|
186 | d.addCallback(lambda ign: download_to_data(n)) |
---|
187 | d.addCallback(_got_data) |
---|
188 | return d |
---|
189 | |
---|
190 | def download_mutable(self, ignored=None): |
---|
191 | n = self.c0.create_node_from_uri(mutable_uri) |
---|
192 | d = n.download_best_version() |
---|
193 | def _got_data(data): |
---|
194 | self.failUnlessEqual(data, mutable_plaintext) |
---|
195 | d.addCallback(_got_data) |
---|
196 | return d |
---|
197 | |
---|
198 | class DownloadTest(_Base, unittest.TestCase): |
---|
199 | def test_download(self): |
---|
200 | self.basedir = self.mktemp() |
---|
201 | self.set_up_grid() |
---|
202 | self.c0 = self.g.clients[0] |
---|
203 | |
---|
204 | # do this to create the shares |
---|
205 | #return self.create_shares() |
---|
206 | |
---|
207 | self.load_shares() |
---|
208 | d = self.download_immutable() |
---|
209 | d.addCallback(self.download_mutable) |
---|
210 | return d |
---|
211 | |
---|
212 | def test_download_failover(self): |
---|
213 | self.basedir = self.mktemp() |
---|
214 | self.set_up_grid() |
---|
215 | self.c0 = self.g.clients[0] |
---|
216 | |
---|
217 | self.load_shares() |
---|
218 | si = uri.from_string(immutable_uri).get_storage_index() |
---|
219 | si_dir = storage_index_to_dir(si) |
---|
220 | |
---|
221 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
222 | d = download_to_data(n) |
---|
223 | def _got_data(data): |
---|
224 | self.failUnlessEqual(data, plaintext) |
---|
225 | d.addCallback(_got_data) |
---|
226 | |
---|
227 | def _clobber_some_shares(ign): |
---|
228 | # find the three shares that were used, and delete them. Then |
---|
229 | # download again, forcing the downloader to fail over to other |
---|
230 | # shares |
---|
231 | for s in n._cnode._node._shares: |
---|
232 | for clientnum in immutable_shares: |
---|
233 | for shnum in immutable_shares[clientnum]: |
---|
234 | if s._shnum == shnum: |
---|
235 | fn = os.path.join(self.get_serverdir(clientnum), |
---|
236 | "shares", si_dir, str(shnum)) |
---|
237 | os.unlink(fn) |
---|
238 | d.addCallback(_clobber_some_shares) |
---|
239 | d.addCallback(lambda ign: download_to_data(n)) |
---|
240 | d.addCallback(_got_data) |
---|
241 | |
---|
242 | def _clobber_most_shares(ign): |
---|
243 | # delete all but one of the shares that are still alive |
---|
244 | live_shares = [s for s in n._cnode._node._shares if s.is_alive()] |
---|
245 | save_me = live_shares[0]._shnum |
---|
246 | for clientnum in immutable_shares: |
---|
247 | for shnum in immutable_shares[clientnum]: |
---|
248 | if shnum == save_me: |
---|
249 | continue |
---|
250 | fn = os.path.join(self.get_serverdir(clientnum), |
---|
251 | "shares", si_dir, str(shnum)) |
---|
252 | if os.path.exists(fn): |
---|
253 | os.unlink(fn) |
---|
254 | # now the download should fail with NotEnoughSharesError |
---|
255 | return self.shouldFail(NotEnoughSharesError, "1shares", None, |
---|
256 | download_to_data, n) |
---|
257 | d.addCallback(_clobber_most_shares) |
---|
258 | |
---|
259 | def _clobber_all_shares(ign): |
---|
260 | # delete the last remaining share |
---|
261 | for clientnum in immutable_shares: |
---|
262 | for shnum in immutable_shares[clientnum]: |
---|
263 | fn = os.path.join(self.get_serverdir(clientnum), |
---|
264 | "shares", si_dir, str(shnum)) |
---|
265 | if os.path.exists(fn): |
---|
266 | os.unlink(fn) |
---|
267 | # now a new download should fail with NoSharesError. We want a |
---|
268 | # new ImmutableFileNode so it will forget about the old shares. |
---|
269 | # If we merely called create_node_from_uri() without first |
---|
270 | # dereferencing the original node, the NodeMaker's _node_cache |
---|
271 | # would give us back the old one. |
---|
272 | n = None |
---|
273 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
274 | return self.shouldFail(NoSharesError, "0shares", None, |
---|
275 | download_to_data, n) |
---|
276 | d.addCallback(_clobber_all_shares) |
---|
277 | return d |
---|
278 | |
---|
279 | def test_lost_servers(self): |
---|
280 | # while downloading a file (after seg[0], before seg[1]), lose the |
---|
281 | # three servers that we were using. The download should switch over |
---|
282 | # to other servers. |
---|
283 | self.basedir = self.mktemp() |
---|
284 | self.set_up_grid() |
---|
285 | self.c0 = self.g.clients[0] |
---|
286 | |
---|
287 | # upload a file with multiple segments, so we can catch the download |
---|
288 | # in the middle. |
---|
289 | u = upload.Data(plaintext, None) |
---|
290 | u.max_segment_size = 70 # 5 segs |
---|
291 | d = self.c0.upload(u) |
---|
292 | def _uploaded(ur): |
---|
293 | self.uri = ur.get_uri() |
---|
294 | self.n = self.c0.create_node_from_uri(self.uri) |
---|
295 | return download_to_data(self.n) |
---|
296 | d.addCallback(_uploaded) |
---|
297 | def _got_data(data): |
---|
298 | self.failUnlessEqual(data, plaintext) |
---|
299 | d.addCallback(_got_data) |
---|
300 | def _kill_some_shares(): |
---|
301 | # find the shares that were used and delete them |
---|
302 | shares = self.n._cnode._node._shares |
---|
303 | self.killed_share_nums = sorted([s._shnum for s in shares]) |
---|
304 | |
---|
305 | # break the RIBucketReader references |
---|
306 | # (we don't break the RIStorageServer references, because that |
---|
307 | # isn't needed to test the current downloader implementation) |
---|
308 | for s in shares: |
---|
309 | s._rref.broken = True |
---|
310 | def _download_again(ign): |
---|
311 | # download again, deleting some shares after the first write |
---|
312 | # to the consumer |
---|
313 | c = StallingConsumer(_kill_some_shares) |
---|
314 | return self.n.read(c) |
---|
315 | d.addCallback(_download_again) |
---|
316 | def _check_failover(c): |
---|
317 | self.failUnlessEqual(b"".join(c.chunks), plaintext) |
---|
318 | shares = self.n._cnode._node._shares |
---|
319 | shnums = sorted([s._shnum for s in shares]) |
---|
320 | self.failIfEqual(shnums, self.killed_share_nums) |
---|
321 | d.addCallback(_check_failover) |
---|
322 | return d |
---|
323 | |
---|
324 | def test_long_offset(self): |
---|
325 | # bug #1154: mplayer doing a seek-to-end results in an offset of type |
---|
326 | # 'long', rather than 'int', and apparently __len__ is required to |
---|
327 | # return an int. Rewrote Spans/DataSpans to provide s.len() instead |
---|
328 | # of len(s) . |
---|
329 | self.basedir = self.mktemp() |
---|
330 | self.set_up_grid() |
---|
331 | self.c0 = self.g.clients[0] |
---|
332 | self.load_shares() |
---|
333 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
334 | |
---|
335 | c = MemoryConsumer() |
---|
336 | d = n.read(c, int(0), int(10)) |
---|
337 | d.addCallback(lambda c: len(b"".join(c.chunks))) |
---|
338 | d.addCallback(lambda size: self.failUnlessEqual(size, 10)) |
---|
339 | return d |
---|
340 | |
---|
341 | def test_badguess(self): |
---|
342 | self.basedir = self.mktemp() |
---|
343 | self.set_up_grid() |
---|
344 | self.c0 = self.g.clients[0] |
---|
345 | self.load_shares() |
---|
346 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
347 | |
---|
348 | # Cause the downloader to guess a segsize that's too low, so it will |
---|
349 | # ask for a segment number that's too high (beyond the end of the |
---|
350 | # real list, causing BadSegmentNumberError), to exercise |
---|
351 | # Segmentation._retry_bad_segment |
---|
352 | n._cnode._maybe_create_download_node() |
---|
353 | n._cnode._node._build_guessed_tables(90) |
---|
354 | |
---|
355 | con1 = MemoryConsumer() |
---|
356 | # plaintext size of 310 bytes, wrong-segsize of 90 bytes, will make |
---|
357 | # us think that file[180:200] is in the third segment (segnum=2), but |
---|
358 | # really there's only one segment |
---|
359 | d = n.read(con1, 180, 20) |
---|
360 | def _done(res): |
---|
361 | self.failUnlessEqual(b"".join(con1.chunks), plaintext[180:200]) |
---|
362 | d.addCallback(_done) |
---|
363 | return d |
---|
364 | |
---|
365 | def test_simultaneous_badguess(self): |
---|
366 | self.basedir = self.mktemp() |
---|
367 | self.set_up_grid() |
---|
368 | self.c0 = self.g.clients[0] |
---|
369 | |
---|
370 | # upload a file with multiple segments, and a non-default segsize, to |
---|
371 | # exercise the offset-guessing code. Because we don't tell the |
---|
372 | # downloader about the unusual segsize, it will guess wrong, and have |
---|
373 | # to do extra roundtrips to get the correct data. |
---|
374 | u = upload.Data(plaintext, None) |
---|
375 | u.max_segment_size = 70 # 5 segs, 8-wide hashtree |
---|
376 | con1 = MemoryConsumer() |
---|
377 | con2 = MemoryConsumer() |
---|
378 | d = self.c0.upload(u) |
---|
379 | def _uploaded(ur): |
---|
380 | n = self.c0.create_node_from_uri(ur.get_uri()) |
---|
381 | d1 = n.read(con1, 70, 20) |
---|
382 | d2 = n.read(con2, 140, 20) |
---|
383 | return defer.gatherResults([d1,d2]) |
---|
384 | d.addCallback(_uploaded) |
---|
385 | def _done(res): |
---|
386 | self.failUnlessEqual(b"".join(con1.chunks), plaintext[70:90]) |
---|
387 | self.failUnlessEqual(b"".join(con2.chunks), plaintext[140:160]) |
---|
388 | d.addCallback(_done) |
---|
389 | return d |
---|
390 | |
---|
391 | def test_simultaneous_goodguess(self): |
---|
392 | self.basedir = self.mktemp() |
---|
393 | self.set_up_grid() |
---|
394 | self.c0 = self.g.clients[0] |
---|
395 | |
---|
396 | # upload a file with multiple segments, and a non-default segsize, to |
---|
397 | # exercise the offset-guessing code. This time we *do* tell the |
---|
398 | # downloader about the unusual segsize, so it can guess right. |
---|
399 | u = upload.Data(plaintext, None) |
---|
400 | u.max_segment_size = 70 # 5 segs, 8-wide hashtree |
---|
401 | con1 = MemoryConsumer() |
---|
402 | con2 = MemoryConsumer() |
---|
403 | d = self.c0.upload(u) |
---|
404 | def _uploaded(ur): |
---|
405 | n = self.c0.create_node_from_uri(ur.get_uri()) |
---|
406 | n._cnode._maybe_create_download_node() |
---|
407 | n._cnode._node._build_guessed_tables(u.max_segment_size) |
---|
408 | d1 = n.read(con1, 70, 20) |
---|
409 | d2 = n.read(con2, 140, 20) |
---|
410 | return defer.gatherResults([d1,d2]) |
---|
411 | d.addCallback(_uploaded) |
---|
412 | def _done(res): |
---|
413 | self.failUnlessEqual(b"".join(con1.chunks), plaintext[70:90]) |
---|
414 | self.failUnlessEqual(b"".join(con2.chunks), plaintext[140:160]) |
---|
415 | d.addCallback(_done) |
---|
416 | return d |
---|
417 | |
---|
418 | def test_sequential_goodguess(self): |
---|
419 | self.basedir = self.mktemp() |
---|
420 | self.set_up_grid() |
---|
421 | self.c0 = self.g.clients[0] |
---|
422 | data = (plaintext*100)[:30000] # multiple of k |
---|
423 | |
---|
424 | # upload a file with multiple segments, and a non-default segsize, to |
---|
425 | # exercise the offset-guessing code. This time we *do* tell the |
---|
426 | # downloader about the unusual segsize, so it can guess right. |
---|
427 | u = upload.Data(data, None) |
---|
428 | u.max_segment_size = 6000 # 5 segs, 8-wide hashtree |
---|
429 | con1 = MemoryConsumer() |
---|
430 | con2 = MemoryConsumer() |
---|
431 | d = self.c0.upload(u) |
---|
432 | def _uploaded(ur): |
---|
433 | n = self.c0.create_node_from_uri(ur.get_uri()) |
---|
434 | n._cnode._maybe_create_download_node() |
---|
435 | n._cnode._node._build_guessed_tables(u.max_segment_size) |
---|
436 | d = n.read(con1, 12000, 20) |
---|
437 | def _read1(ign): |
---|
438 | self.failUnlessEqual(b"".join(con1.chunks), data[12000:12020]) |
---|
439 | return n.read(con2, 24000, 20) |
---|
440 | d.addCallback(_read1) |
---|
441 | def _read2(ign): |
---|
442 | self.failUnlessEqual(b"".join(con2.chunks), data[24000:24020]) |
---|
443 | d.addCallback(_read2) |
---|
444 | return d |
---|
445 | d.addCallback(_uploaded) |
---|
446 | return d |
---|
447 | |
---|
448 | |
---|
449 | def test_simultaneous_get_blocks(self): |
---|
450 | self.basedir = self.mktemp() |
---|
451 | self.set_up_grid() |
---|
452 | self.c0 = self.g.clients[0] |
---|
453 | |
---|
454 | self.load_shares() |
---|
455 | stay_empty = [] |
---|
456 | |
---|
457 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
458 | d = download_to_data(n) |
---|
459 | def _use_shares(ign): |
---|
460 | shares = list(n._cnode._node._shares) |
---|
461 | s0 = shares[0] |
---|
462 | # make sure .cancel works too |
---|
463 | o0 = s0.get_block(0) |
---|
464 | o0.subscribe(lambda **kwargs: stay_empty.append(kwargs)) |
---|
465 | o1 = s0.get_block(0) |
---|
466 | o2 = s0.get_block(0) |
---|
467 | o0.cancel() |
---|
468 | o3 = s0.get_block(1) # state=BADSEGNUM |
---|
469 | d1 = defer.Deferred() |
---|
470 | d2 = defer.Deferred() |
---|
471 | d3 = defer.Deferred() |
---|
472 | o1.subscribe(lambda **kwargs: d1.callback(kwargs)) |
---|
473 | o2.subscribe(lambda **kwargs: d2.callback(kwargs)) |
---|
474 | o3.subscribe(lambda **kwargs: d3.callback(kwargs)) |
---|
475 | return defer.gatherResults([d1,d2,d3]) |
---|
476 | d.addCallback(_use_shares) |
---|
477 | def _done(res): |
---|
478 | r1,r2,r3 = res |
---|
479 | self.failUnlessEqual(r1["state"], "COMPLETE") |
---|
480 | self.failUnlessEqual(r2["state"], "COMPLETE") |
---|
481 | self.failUnlessEqual(r3["state"], "BADSEGNUM") |
---|
482 | self.failUnless("block" in r1) |
---|
483 | self.failUnless("block" in r2) |
---|
484 | self.failIf(stay_empty) |
---|
485 | d.addCallback(_done) |
---|
486 | return d |
---|
487 | |
---|
488 | def test_simul_1fail_1cancel(self): |
---|
489 | # This exercises an mplayer behavior in ticket #1154. I believe that |
---|
490 | # mplayer made two simultaneous webapi GET requests: first one for an |
---|
491 | # index region at the end of the (mp3/video) file, then one for the |
---|
492 | # first block of the file (the order doesn't really matter). All GETs |
---|
493 | # failed (NoSharesError) because of the type(__len__)==long bug. Each |
---|
494 | # GET submitted a DownloadNode.get_segment() request, which was |
---|
495 | # queued by the DN (DN._segment_requests), so the second one was |
---|
496 | # blocked waiting on the first one. When the first one failed, |
---|
497 | # DN.fetch_failed() was invoked, which errbacks the first GET, but |
---|
498 | # left the other one hanging (the lost-progress bug mentioned in |
---|
499 | # #1154 comment 10) |
---|
500 | # |
---|
501 | # Then mplayer sees that the index region GET failed, so it cancels |
---|
502 | # the first-block GET (by closing the HTTP request), triggering |
---|
503 | # stopProducer. The second GET was waiting in the Deferred (between |
---|
504 | # n.get_segment() and self._request_retired), so its |
---|
505 | # _cancel_segment_request was active, so was invoked. However, |
---|
506 | # DN._active_segment was None since it was not working on any segment |
---|
507 | # at that time, hence the error in #1154. |
---|
508 | |
---|
509 | self.basedir = self.mktemp() |
---|
510 | self.set_up_grid() |
---|
511 | self.c0 = self.g.clients[0] |
---|
512 | |
---|
513 | # upload a file with multiple segments, so we can catch the download |
---|
514 | # in the middle. Tell the downloader, so it can guess correctly. |
---|
515 | u = upload.Data(plaintext, None) |
---|
516 | u.max_segment_size = 70 # 5 segs |
---|
517 | d = self.c0.upload(u) |
---|
518 | def _uploaded(ur): |
---|
519 | # corrupt all the shares so the download will fail |
---|
520 | def _corruptor(s, debug=False): |
---|
521 | which = 48 # first byte of block0 |
---|
522 | return s[:which] + bchr(ord(s[which:which+1])^0x01) + s[which+1:] |
---|
523 | self.corrupt_all_shares(ur.get_uri(), _corruptor) |
---|
524 | n = self.c0.create_node_from_uri(ur.get_uri()) |
---|
525 | n._cnode._maybe_create_download_node() |
---|
526 | n._cnode._node._build_guessed_tables(u.max_segment_size) |
---|
527 | con1 = MemoryConsumer() |
---|
528 | con2 = MemoryConsumer() |
---|
529 | d = n.read(con1, int(0), int(20)) |
---|
530 | d2 = n.read(con2, int(140), int(20)) |
---|
531 | # con2 will be cancelled, so d2 should fail with DownloadStopped |
---|
532 | def _con2_should_not_succeed(res): |
---|
533 | self.fail("the second read should not have succeeded") |
---|
534 | def _con2_failed(f): |
---|
535 | self.failUnless(f.check(DownloadStopped)) |
---|
536 | d2.addCallbacks(_con2_should_not_succeed, _con2_failed) |
---|
537 | |
---|
538 | def _con1_should_not_succeed(res): |
---|
539 | self.fail("the first read should not have succeeded") |
---|
540 | def _con1_failed(f): |
---|
541 | self.failUnless(f.check(NoSharesError)) |
---|
542 | con2.producer.stopProducing() |
---|
543 | return d2 |
---|
544 | d.addCallbacks(_con1_should_not_succeed, _con1_failed) |
---|
545 | return d |
---|
546 | d.addCallback(_uploaded) |
---|
547 | return d |
---|
548 | |
---|
549 | def test_simultaneous_onefails(self): |
---|
550 | self.basedir = self.mktemp() |
---|
551 | self.set_up_grid() |
---|
552 | self.c0 = self.g.clients[0] |
---|
553 | |
---|
554 | # upload a file with multiple segments, so we can catch the download |
---|
555 | # in the middle. Tell the downloader, so it can guess correctly. |
---|
556 | u = upload.Data(plaintext, None) |
---|
557 | u.max_segment_size = 70 # 5 segs |
---|
558 | d = self.c0.upload(u) |
---|
559 | def _uploaded(ur): |
---|
560 | # corrupt all the shares so the download will fail |
---|
561 | def _corruptor(s, debug=False): |
---|
562 | which = 48 # first byte of block0 |
---|
563 | return s[:which] + bchr(ord(s[which:which+1])^0x01) + s[which+1:] |
---|
564 | self.corrupt_all_shares(ur.get_uri(), _corruptor) |
---|
565 | n = self.c0.create_node_from_uri(ur.get_uri()) |
---|
566 | n._cnode._maybe_create_download_node() |
---|
567 | n._cnode._node._build_guessed_tables(u.max_segment_size) |
---|
568 | con1 = MemoryConsumer() |
---|
569 | con2 = MemoryConsumer() |
---|
570 | d = n.read(con1, int(0), int(20)) |
---|
571 | d2 = n.read(con2, int(140), int(20)) |
---|
572 | # con2 should wait for con1 to fail and then con2 should succeed. |
---|
573 | # In particular, we should not lose progress. If this test fails, |
---|
574 | # it will fail with a timeout error. |
---|
575 | def _con2_should_succeed(res): |
---|
576 | # this should succeed because we only corrupted the first |
---|
577 | # segment of each share. The segment that holds [140:160] is |
---|
578 | # fine, as are the hash chains and UEB. |
---|
579 | self.failUnlessEqual(b"".join(con2.chunks), plaintext[140:160]) |
---|
580 | d2.addCallback(_con2_should_succeed) |
---|
581 | |
---|
582 | def _con1_should_not_succeed(res): |
---|
583 | self.fail("the first read should not have succeeded") |
---|
584 | def _con1_failed(f): |
---|
585 | self.failUnless(f.check(NoSharesError)) |
---|
586 | # we *don't* cancel the second one here: this exercises a |
---|
587 | # lost-progress bug from #1154. We just wait for it to |
---|
588 | # succeed. |
---|
589 | return d2 |
---|
590 | d.addCallbacks(_con1_should_not_succeed, _con1_failed) |
---|
591 | return d |
---|
592 | d.addCallback(_uploaded) |
---|
593 | return d |
---|
594 | |
---|
595 | def test_download_no_overrun(self): |
---|
596 | self.basedir = self.mktemp() |
---|
597 | self.set_up_grid() |
---|
598 | self.c0 = self.g.clients[0] |
---|
599 | |
---|
600 | self.load_shares() |
---|
601 | |
---|
602 | # tweak the client's copies of server-version data, so it believes |
---|
603 | # that they're old and can't handle reads that overrun the length of |
---|
604 | # the share. This exercises a different code path. |
---|
605 | for s in self.c0.storage_broker.get_connected_servers(): |
---|
606 | v = s.get_version() |
---|
607 | v1 = v[b"http://allmydata.org/tahoe/protocols/storage/v1"] |
---|
608 | v1[b"tolerates-immutable-read-overrun"] = False |
---|
609 | |
---|
610 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
611 | d = download_to_data(n) |
---|
612 | def _got_data(data): |
---|
613 | self.failUnlessEqual(data, plaintext) |
---|
614 | d.addCallback(_got_data) |
---|
615 | return d |
---|
616 | |
---|
617 | def test_download_segment(self): |
---|
618 | self.basedir = self.mktemp() |
---|
619 | self.set_up_grid() |
---|
620 | self.c0 = self.g.clients[0] |
---|
621 | self.load_shares() |
---|
622 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
623 | cn = n._cnode |
---|
624 | (d,c) = cn.get_segment(0) |
---|
625 | def _got_segment(offset_and_data_and_decodetime): |
---|
626 | (offset, data, decodetime) = offset_and_data_and_decodetime |
---|
627 | self.failUnlessEqual(offset, 0) |
---|
628 | self.failUnlessEqual(len(data), len(plaintext)) |
---|
629 | d.addCallback(_got_segment) |
---|
630 | return d |
---|
631 | |
---|
632 | def test_download_segment_cancel(self): |
---|
633 | self.basedir = self.mktemp() |
---|
634 | self.set_up_grid() |
---|
635 | self.c0 = self.g.clients[0] |
---|
636 | self.load_shares() |
---|
637 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
638 | cn = n._cnode |
---|
639 | (d,c) = cn.get_segment(0) |
---|
640 | fired = [] |
---|
641 | d.addCallback(fired.append) |
---|
642 | c.cancel() |
---|
643 | d = fireEventually() |
---|
644 | d.addCallback(flushEventualQueue) |
---|
645 | def _check(ign): |
---|
646 | self.failUnlessEqual(fired, []) |
---|
647 | d.addCallback(_check) |
---|
648 | return d |
---|
649 | |
---|
650 | def test_download_bad_segment(self): |
---|
651 | self.basedir = self.mktemp() |
---|
652 | self.set_up_grid() |
---|
653 | self.c0 = self.g.clients[0] |
---|
654 | self.load_shares() |
---|
655 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
656 | cn = n._cnode |
---|
657 | def _try_download(): |
---|
658 | (d,c) = cn.get_segment(1) |
---|
659 | return d |
---|
660 | d = self.shouldFail(BadSegmentNumberError, "badseg", |
---|
661 | "segnum=1, numsegs=1", |
---|
662 | _try_download) |
---|
663 | return d |
---|
664 | |
---|
665 | def test_download_segment_terminate(self): |
---|
666 | self.basedir = self.mktemp() |
---|
667 | self.set_up_grid() |
---|
668 | self.c0 = self.g.clients[0] |
---|
669 | self.load_shares() |
---|
670 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
671 | cn = n._cnode |
---|
672 | (d,c) = cn.get_segment(0) |
---|
673 | fired = [] |
---|
674 | d.addCallback(fired.append) |
---|
675 | self.c0.terminator.disownServiceParent() |
---|
676 | d = fireEventually() |
---|
677 | d.addCallback(flushEventualQueue) |
---|
678 | def _check(ign): |
---|
679 | self.failUnlessEqual(fired, []) |
---|
680 | d.addCallback(_check) |
---|
681 | return d |
---|
682 | |
---|
683 | def test_pause(self): |
---|
684 | self.basedir = self.mktemp() |
---|
685 | self.set_up_grid() |
---|
686 | self.c0 = self.g.clients[0] |
---|
687 | self.load_shares() |
---|
688 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
689 | c = PausingConsumer() |
---|
690 | d = n.read(c) |
---|
691 | def _downloaded(mc): |
---|
692 | newdata = b"".join(mc.chunks) |
---|
693 | self.failUnlessEqual(newdata, plaintext) |
---|
694 | d.addCallback(_downloaded) |
---|
695 | return d |
---|
696 | |
---|
697 | def test_pause_then_stop(self): |
---|
698 | self.basedir = self.mktemp() |
---|
699 | self.set_up_grid() |
---|
700 | self.c0 = self.g.clients[0] |
---|
701 | self.load_shares() |
---|
702 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
703 | c = PausingAndStoppingConsumer() |
---|
704 | d = self.shouldFail(DownloadStopped, "test_pause_then_stop", |
---|
705 | "our Consumer called stopProducing()", |
---|
706 | n.read, c) |
---|
707 | return d |
---|
708 | |
---|
709 | def test_stop(self): |
---|
710 | # use a download target that stops after the first segment (#473) |
---|
711 | self.basedir = self.mktemp() |
---|
712 | self.set_up_grid() |
---|
713 | self.c0 = self.g.clients[0] |
---|
714 | self.load_shares() |
---|
715 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
716 | c = StoppingConsumer() |
---|
717 | d = self.shouldFail(DownloadStopped, "test_stop", |
---|
718 | "our Consumer called stopProducing()", |
---|
719 | n.read, c) |
---|
720 | return d |
---|
721 | |
---|
722 | def test_stop_immediately(self): |
---|
723 | # and a target that stops right after registerProducer (maybe #1154) |
---|
724 | self.basedir = self.mktemp() |
---|
725 | self.set_up_grid() |
---|
726 | self.c0 = self.g.clients[0] |
---|
727 | self.load_shares() |
---|
728 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
729 | |
---|
730 | c = ImmediatelyStoppingConsumer() # stops after registerProducer |
---|
731 | d = self.shouldFail(DownloadStopped, "test_stop_immediately", |
---|
732 | "our Consumer called stopProducing()", |
---|
733 | n.read, c) |
---|
734 | return d |
---|
735 | |
---|
736 | def test_stop_immediately2(self): |
---|
737 | # and a target that stops right after registerProducer (maybe #1154) |
---|
738 | self.basedir = self.mktemp() |
---|
739 | self.set_up_grid() |
---|
740 | self.c0 = self.g.clients[0] |
---|
741 | self.load_shares() |
---|
742 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
743 | |
---|
744 | c = MemoryConsumer() |
---|
745 | d0 = n.read(c) |
---|
746 | c.producer.stopProducing() |
---|
747 | d = self.shouldFail(DownloadStopped, "test_stop_immediately", |
---|
748 | "our Consumer called stopProducing()", |
---|
749 | lambda: d0) |
---|
750 | return d |
---|
751 | |
---|
752 | def test_download_segment_bad_ciphertext_hash(self): |
---|
753 | # The crypttext_hash_tree asserts the integrity of the decoded |
---|
754 | # ciphertext, and exists to detect two sorts of problems. The first |
---|
755 | # is a bug in zfec decode. The second is the "two-sided t-shirt" |
---|
756 | # attack (found by Christian Grothoff), in which a malicious uploader |
---|
757 | # creates two sets of shares (one for file A, second for file B), |
---|
758 | # uploads a combination of them (shares 0-4 of A, 5-9 of B), and then |
---|
759 | # builds an otherwise normal UEB around those shares: their goal is |
---|
760 | # to give their victim a filecap which sometimes downloads the good A |
---|
761 | # contents, and sometimes the bad B contents, depending upon which |
---|
762 | # servers/shares they can get to. Having a hash of the ciphertext |
---|
763 | # forces them to commit to exactly one version. (Christian's prize |
---|
764 | # for finding this problem was a t-shirt with two sides: the shares |
---|
765 | # of file A on the front, B on the back). |
---|
766 | |
---|
767 | # creating a set of shares with this property is too hard, although |
---|
768 | # it'd be nice to do so and confirm our fix. (it requires a lot of |
---|
769 | # tampering with the uploader). So instead, we just damage the |
---|
770 | # decoder. The tail decoder is rebuilt each time, so we need to use a |
---|
771 | # file with multiple segments. |
---|
772 | self.basedir = self.mktemp() |
---|
773 | self.set_up_grid() |
---|
774 | self.c0 = self.g.clients[0] |
---|
775 | |
---|
776 | u = upload.Data(plaintext, None) |
---|
777 | u.max_segment_size = 60 # 6 segs |
---|
778 | d = self.c0.upload(u) |
---|
779 | def _uploaded(ur): |
---|
780 | n = self.c0.create_node_from_uri(ur.get_uri()) |
---|
781 | n._cnode._maybe_create_download_node() |
---|
782 | n._cnode._node._build_guessed_tables(u.max_segment_size) |
---|
783 | |
---|
784 | d = download_to_data(n) |
---|
785 | def _break_codec(data): |
---|
786 | # the codec isn't created until the UEB is retrieved |
---|
787 | node = n._cnode._node |
---|
788 | vcap = node._verifycap |
---|
789 | k, N = vcap.needed_shares, vcap.total_shares |
---|
790 | bad_codec = BrokenDecoder() |
---|
791 | bad_codec.set_params(node.segment_size, k, N) |
---|
792 | node._codec = bad_codec |
---|
793 | d.addCallback(_break_codec) |
---|
794 | # now try to download it again. The broken codec will provide |
---|
795 | # ciphertext that fails the hash test. |
---|
796 | d.addCallback(lambda ign: |
---|
797 | self.shouldFail(BadCiphertextHashError, "badhash", |
---|
798 | "hash failure in " |
---|
799 | "ciphertext_hash_tree: segnum=0", |
---|
800 | download_to_data, n)) |
---|
801 | return d |
---|
802 | d.addCallback(_uploaded) |
---|
803 | return d |
---|
804 | |
---|
805 | def OFFtest_download_segment_XXX(self): |
---|
806 | self.basedir = self.mktemp() |
---|
807 | self.set_up_grid() |
---|
808 | self.c0 = self.g.clients[0] |
---|
809 | |
---|
810 | # upload a file with multiple segments, and a non-default segsize, to |
---|
811 | # exercise the offset-guessing code. This time we *do* tell the |
---|
812 | # downloader about the unusual segsize, so it can guess right. |
---|
813 | u = upload.Data(plaintext, None) |
---|
814 | u.max_segment_size = 70 # 5 segs, 8-wide hashtree |
---|
815 | con1 = MemoryConsumer() |
---|
816 | con2 = MemoryConsumer() |
---|
817 | d = self.c0.upload(u) |
---|
818 | def _uploaded(ur): |
---|
819 | n = self.c0.create_node_from_uri(ur.get_uri()) |
---|
820 | n._cnode._maybe_create_download_node() |
---|
821 | n._cnode._node._build_guessed_tables(u.max_segment_size) |
---|
822 | d1 = n.read(con1, 70, 20) |
---|
823 | #d2 = n.read(con2, 140, 20) |
---|
824 | d2 = defer.succeed(None) |
---|
825 | return defer.gatherResults([d1,d2]) |
---|
826 | d.addCallback(_uploaded) |
---|
827 | def _done(res): |
---|
828 | self.failUnlessEqual(b"".join(con1.chunks), plaintext[70:90]) |
---|
829 | self.failUnlessEqual(b"".join(con2.chunks), plaintext[140:160]) |
---|
830 | #d.addCallback(_done) |
---|
831 | return d |
---|
832 | |
---|
833 | def test_duplicate_shares(self): |
---|
834 | self.basedir = self.mktemp() |
---|
835 | self.set_up_grid() |
---|
836 | self.c0 = self.g.clients[0] |
---|
837 | |
---|
838 | self.load_shares() |
---|
839 | # make sure everybody has a copy of sh0. The second server contacted |
---|
840 | # will report two shares, and the ShareFinder will handle the |
---|
841 | # duplicate by attaching both to the same CommonShare instance. |
---|
842 | si = uri.from_string(immutable_uri).get_storage_index() |
---|
843 | si_dir = storage_index_to_dir(si) |
---|
844 | sh0_file = [sharefile |
---|
845 | for (shnum, serverid, sharefile) |
---|
846 | in self.find_uri_shares(immutable_uri) |
---|
847 | if shnum == 0][0] |
---|
848 | sh0_data = open(sh0_file, "rb").read() |
---|
849 | for clientnum in immutable_shares: |
---|
850 | if 0 in immutable_shares[clientnum]: |
---|
851 | continue |
---|
852 | cdir = self.get_serverdir(clientnum) |
---|
853 | target = os.path.join(cdir, "shares", si_dir, "0") |
---|
854 | outf = open(target, "wb") |
---|
855 | outf.write(sh0_data) |
---|
856 | outf.close() |
---|
857 | |
---|
858 | d = self.download_immutable() |
---|
859 | return d |
---|
860 | |
---|
861 | def test_verifycap(self): |
---|
862 | self.basedir = self.mktemp() |
---|
863 | self.set_up_grid() |
---|
864 | self.c0 = self.g.clients[0] |
---|
865 | self.load_shares() |
---|
866 | |
---|
867 | n = self.c0.create_node_from_uri(immutable_uri) |
---|
868 | vcap = n.get_verify_cap().to_string() |
---|
869 | vn = self.c0.create_node_from_uri(vcap) |
---|
870 | d = download_to_data(vn) |
---|
871 | def _got_ciphertext(ciphertext): |
---|
872 | self.failUnlessEqual(len(ciphertext), len(plaintext)) |
---|
873 | self.failIfEqual(ciphertext, plaintext) |
---|
874 | d.addCallback(_got_ciphertext) |
---|
875 | return d |
---|
876 | |
---|
877 | class BrokenDecoder(CRSDecoder): |
---|
878 | def decode(self, shares, shareids): |
---|
879 | d = CRSDecoder.decode(self, shares, shareids) |
---|
880 | def _decoded(buffers): |
---|
881 | def _corruptor(s, which): |
---|
882 | return s[:which] + bchr(ord(s[which:which+1])^0x01) + s[which+1:] |
---|
883 | buffers[0] = _corruptor(buffers[0], 0) # flip lsb of first byte |
---|
884 | return buffers |
---|
885 | d.addCallback(_decoded) |
---|
886 | return d |
---|
887 | |
---|
888 | |
---|
889 | class PausingConsumer(MemoryConsumer): |
---|
890 | def __init__(self): |
---|
891 | MemoryConsumer.__init__(self) |
---|
892 | self.size = 0 |
---|
893 | self.writes = 0 |
---|
894 | def write(self, data): |
---|
895 | self.size += len(data) |
---|
896 | self.writes += 1 |
---|
897 | if self.writes <= 2: |
---|
898 | # we happen to use 4 segments, and want to avoid pausing on the |
---|
899 | # last one (since then the _unpause timer will still be running) |
---|
900 | self.producer.pauseProducing() |
---|
901 | reactor.callLater(0.1, self._unpause) |
---|
902 | return MemoryConsumer.write(self, data) |
---|
903 | def _unpause(self): |
---|
904 | self.producer.resumeProducing() |
---|
905 | |
---|
906 | class PausingAndStoppingConsumer(PausingConsumer): |
---|
907 | debug_stopped = False |
---|
908 | def write(self, data): |
---|
909 | if self.debug_stopped: |
---|
910 | raise Exception("I'm stopped, don't write to me") |
---|
911 | self.producer.pauseProducing() |
---|
912 | eventually(self._stop) |
---|
913 | def _stop(self): |
---|
914 | self.debug_stopped = True |
---|
915 | self.producer.stopProducing() |
---|
916 | |
---|
917 | class StoppingConsumer(PausingConsumer): |
---|
918 | def write(self, data): |
---|
919 | self.producer.stopProducing() |
---|
920 | |
---|
921 | class ImmediatelyStoppingConsumer(MemoryConsumer): |
---|
922 | def registerProducer(self, p, streaming): |
---|
923 | MemoryConsumer.registerProducer(self, p, streaming) |
---|
924 | self.producer.stopProducing() |
---|
925 | |
---|
926 | class StallingConsumer(MemoryConsumer): |
---|
927 | def __init__(self, halfway_cb): |
---|
928 | MemoryConsumer.__init__(self) |
---|
929 | self.halfway_cb = halfway_cb |
---|
930 | self.writes = 0 |
---|
931 | def write(self, data): |
---|
932 | self.writes += 1 |
---|
933 | if self.writes == 1: |
---|
934 | self.halfway_cb() |
---|
935 | return MemoryConsumer.write(self, data) |
---|
936 | |
---|
937 | class Corruption(_Base, unittest.TestCase): |
---|
938 | |
---|
939 | def _corrupt_flip(self, ign, imm_uri, which): |
---|
940 | log.msg("corrupt %d" % which) |
---|
941 | def _corruptor(s, debug=False): |
---|
942 | return s[:which] + bchr(ord(s[which:which+1])^0x01) + s[which+1:] |
---|
943 | self.corrupt_shares_numbered(imm_uri, [2], _corruptor) |
---|
944 | |
---|
945 | def _corrupt_set(self, ign, imm_uri, which, newvalue): |
---|
946 | # type: (Any, bytes, int, int) -> None |
---|
947 | """ |
---|
948 | Replace a single byte share file number 2 for the given capability with a |
---|
949 | new byte. |
---|
950 | |
---|
951 | :param imm_uri: Corrupt share number 2 belonging to this capability. |
---|
952 | :param which: The byte position to replace. |
---|
953 | :param newvalue: The new byte value to set in the share. |
---|
954 | """ |
---|
955 | log.msg("corrupt %d" % which) |
---|
956 | def _corruptor(s, debug=False): |
---|
957 | return s[:which] + bchr(newvalue) + s[which+1:] |
---|
958 | self.corrupt_shares_numbered(imm_uri, [2], _corruptor) |
---|
959 | |
---|
960 | def test_each_byte(self): |
---|
961 | """ |
---|
962 | Test share selection behavior of the downloader in the face of certain |
---|
963 | kinds of data corruption. |
---|
964 | |
---|
965 | 1. upload a small share to the no-network grid |
---|
966 | 2. read all of the resulting share files out of the no-network storage servers |
---|
967 | 3. for each of |
---|
968 | |
---|
969 | a. each byte of the share file version field |
---|
970 | b. each byte of the immutable share version field |
---|
971 | c. each byte of the immutable share data offset field |
---|
972 | d. the most significant byte of the block_shares offset field |
---|
973 | e. one of the bytes of one of the merkle trees |
---|
974 | f. one of the bytes of the share hashes list |
---|
975 | |
---|
976 | i. flip the least significant bit in all of the the share files |
---|
977 | ii. perform the download/check/restore process |
---|
978 | |
---|
979 | 4. add 2 ** 24 to the share file version number |
---|
980 | 5. perform the download/check/restore process |
---|
981 | |
---|
982 | 6. add 2 ** 24 to the share version number |
---|
983 | 7. perform the download/check/restore process |
---|
984 | |
---|
985 | The download/check/restore process is: |
---|
986 | |
---|
987 | 1. attempt to download the data |
---|
988 | 2. assert that the recovered plaintext is correct |
---|
989 | 3. assert that only the "correct" share numbers were used to reconstruct the plaintext |
---|
990 | 4. restore all of the share files to their pristine condition |
---|
991 | """ |
---|
992 | # Setting catalog_detection=True performs an exhaustive test of the |
---|
993 | # Downloader's response to corruption in the lsb of each byte of the |
---|
994 | # 2070-byte share, with two goals: make sure we tolerate all forms of |
---|
995 | # corruption (i.e. don't hang or return bad data), and make a list of |
---|
996 | # which bytes can be corrupted without influencing the download |
---|
997 | # (since we don't need every byte of the share). That takes 50s to |
---|
998 | # run on my laptop and doesn't have any actual asserts, so we don't |
---|
999 | # normally do that. |
---|
1000 | self.catalog_detection = False |
---|
1001 | |
---|
1002 | self.basedir = "download/Corruption/each_byte" |
---|
1003 | self.set_up_grid() |
---|
1004 | self.c0 = self.g.clients[0] |
---|
1005 | |
---|
1006 | # to exercise the block-hash-tree code properly, we need to have |
---|
1007 | # multiple segments. We don't tell the downloader about the different |
---|
1008 | # segsize, so it guesses wrong and must do extra roundtrips. |
---|
1009 | u = upload.Data(plaintext, None) |
---|
1010 | u.max_segment_size = 120 # 3 segs, 4-wide hashtree |
---|
1011 | |
---|
1012 | if self.catalog_detection: |
---|
1013 | undetected = spans.Spans() |
---|
1014 | |
---|
1015 | def _download(ign, imm_uri, which, expected): |
---|
1016 | n = self.c0.create_node_from_uri(imm_uri) |
---|
1017 | n._cnode._maybe_create_download_node() |
---|
1018 | # for this test to work, we need to have a new Node each time. |
---|
1019 | # Make sure the NodeMaker's weakcache hasn't interfered. |
---|
1020 | assert not n._cnode._node._shares |
---|
1021 | d = download_to_data(n) |
---|
1022 | def _got_data(data): |
---|
1023 | self.failUnlessEqual(data, plaintext) |
---|
1024 | shnums = sorted([s._shnum for s in n._cnode._node._shares]) |
---|
1025 | no_sh2 = bool(2 not in shnums) |
---|
1026 | sh2 = [s for s in n._cnode._node._shares if s._shnum == 2] |
---|
1027 | sh2_had_corruption = False |
---|
1028 | if sh2 and sh2[0].had_corruption: |
---|
1029 | sh2_had_corruption = True |
---|
1030 | num_needed = len(n._cnode._node._shares) |
---|
1031 | if self.catalog_detection: |
---|
1032 | detected = no_sh2 or sh2_had_corruption or (num_needed!=3) |
---|
1033 | if not detected: |
---|
1034 | undetected.add(which, 1) |
---|
1035 | if expected == "no-sh2": |
---|
1036 | self.failIfIn(2, shnums) |
---|
1037 | elif expected == "2bad-need-3": |
---|
1038 | self.failIf(no_sh2) |
---|
1039 | self.failUnless(sh2[0].had_corruption) |
---|
1040 | self.failUnlessEqual(num_needed, 3) |
---|
1041 | elif expected == "need-4th": |
---|
1042 | # XXX check with warner; what relevance does this |
---|
1043 | # have for the "need-4th" stuff? |
---|
1044 | #self.failIf(no_sh2) |
---|
1045 | #self.failUnless(sh2[0].had_corruption) |
---|
1046 | self.failIfEqual(num_needed, 3) |
---|
1047 | d.addCallback(_got_data) |
---|
1048 | return d |
---|
1049 | |
---|
1050 | |
---|
1051 | d = self.c0.upload(u) |
---|
1052 | def _uploaded(ur): |
---|
1053 | imm_uri = ur.get_uri() |
---|
1054 | self.shares = self.copy_shares(imm_uri) |
---|
1055 | d = defer.succeed(None) |
---|
1056 | # 'victims' is a list of corruption tests to run. Each one flips |
---|
1057 | # the low-order bit of the specified offset in the share file (so |
---|
1058 | # offset=0 is the MSB of the container version, offset=15 is the |
---|
1059 | # LSB of the share version, offset=24 is the MSB of the |
---|
1060 | # data-block-offset, and offset=48 is the first byte of the first |
---|
1061 | # data-block). Each one also specifies what sort of corruption |
---|
1062 | # we're expecting to see. |
---|
1063 | no_sh2_victims = [0,1,2,3] # container version |
---|
1064 | need3_victims = [ ] # none currently in this category |
---|
1065 | # when the offsets are corrupted, the Share will be unable to |
---|
1066 | # retrieve the data it wants (because it thinks that data lives |
---|
1067 | # off in the weeds somewhere), and Share treats DataUnavailable |
---|
1068 | # as abandon-this-share, so in general we'll be forced to look |
---|
1069 | # for a 4th share. |
---|
1070 | need_4th_victims = [12,13,14,15, # offset[data] |
---|
1071 | 24,25,26,27, # offset[block_hashes] |
---|
1072 | ] |
---|
1073 | need_4th_victims.append(36) # block data |
---|
1074 | # when corrupting hash trees, we must corrupt a value that isn't |
---|
1075 | # directly set from somewhere else. Since we download data from |
---|
1076 | # seg2, corrupt something on its hash chain, like [2] (the |
---|
1077 | # right-hand child of the root) |
---|
1078 | need_4th_victims.append(600+2*32) # block_hashes[2] |
---|
1079 | # Share.loop is pretty conservative: it abandons the share at the |
---|
1080 | # first sign of corruption. It doesn't strictly need to be this |
---|
1081 | # way: if the UEB were corrupt, we could still get good block |
---|
1082 | # data from that share, as long as there was a good copy of the |
---|
1083 | # UEB elsewhere. If this behavior is relaxed, then corruption in |
---|
1084 | # the following fields (which are present in multiple shares) |
---|
1085 | # should fall into the "need3_victims" case instead of the |
---|
1086 | # "need_4th_victims" case. |
---|
1087 | need_4th_victims.append(824) # share_hashes |
---|
1088 | corrupt_me = ([(i,"no-sh2") for i in no_sh2_victims] + |
---|
1089 | [(i, "2bad-need-3") for i in need3_victims] + |
---|
1090 | [(i, "need-4th") for i in need_4th_victims]) |
---|
1091 | if self.catalog_detection: |
---|
1092 | share_len = len(list(self.shares.values())[0]) |
---|
1093 | corrupt_me = [(i, "") for i in range(share_len)] |
---|
1094 | # This is a work around for ticket #2024. |
---|
1095 | corrupt_me = corrupt_me[0:8]+corrupt_me[12:] |
---|
1096 | for i,expected in corrupt_me: |
---|
1097 | # All these tests result in a successful download. What we're |
---|
1098 | # measuring is how many shares the downloader had to use. |
---|
1099 | d.addCallback(self._corrupt_flip, imm_uri, i) |
---|
1100 | d.addCallback(_download, imm_uri, i, expected) |
---|
1101 | d.addCallback(lambda ign: self.restore_all_shares(self.shares)) |
---|
1102 | d.addCallback(fireEventually) |
---|
1103 | corrupt_values = [ |
---|
1104 | # Make the container version for share number 2 look |
---|
1105 | # unsupported. If you add support for immutable share file |
---|
1106 | # version number much past 16 million then you will have to |
---|
1107 | # update this test. Also maybe you have other problems. |
---|
1108 | (1, 255, "no-sh2"), |
---|
1109 | # Make the immutable share number 2 (not the container, the |
---|
1110 | # thing inside the container) look unsupported. Ditto the |
---|
1111 | # above about version numbers in the ballpark of 16 million. |
---|
1112 | (13, 255, "need-4th"), |
---|
1113 | ] |
---|
1114 | for i,newvalue,expected in corrupt_values: |
---|
1115 | d.addCallback(self._corrupt_set, imm_uri, i, newvalue) |
---|
1116 | d.addCallback(_download, imm_uri, i, expected) |
---|
1117 | d.addCallback(lambda ign: self.restore_all_shares(self.shares)) |
---|
1118 | d.addCallback(fireEventually) |
---|
1119 | return d |
---|
1120 | d.addCallback(_uploaded) |
---|
1121 | def _show_results(ign): |
---|
1122 | share_len = len(list(self.shares.values())[0]) |
---|
1123 | print() |
---|
1124 | print("of [0:%d], corruption ignored in %s" % |
---|
1125 | (share_len, undetected.dump())) |
---|
1126 | if self.catalog_detection: |
---|
1127 | d.addCallback(_show_results) |
---|
1128 | # of [0:2070], corruption ignored in len=1133: |
---|
1129 | # [4-11],[16-23],[28-31],[152-439],[600-663],[1309-2069] |
---|
1130 | # [4-11]: container sizes |
---|
1131 | # [16-23]: share block/data sizes |
---|
1132 | # [152-375]: plaintext hash tree |
---|
1133 | # [376-408]: crypttext_hash_tree[0] (root) |
---|
1134 | # [408-439]: crypttext_hash_tree[1] (computed) |
---|
1135 | # [600-631]: block hash tree[0] (root) |
---|
1136 | # [632-663]: block hash tree[1] (computed) |
---|
1137 | # [1309-]: reserved+unused UEB space |
---|
1138 | return d |
---|
1139 | |
---|
1140 | def test_failure(self): |
---|
1141 | # this test corrupts all shares in the same way, and asserts that the |
---|
1142 | # download fails. |
---|
1143 | |
---|
1144 | self.basedir = "download/Corruption/failure" |
---|
1145 | self.set_up_grid() |
---|
1146 | self.c0 = self.g.clients[0] |
---|
1147 | |
---|
1148 | # to exercise the block-hash-tree code properly, we need to have |
---|
1149 | # multiple segments. We don't tell the downloader about the different |
---|
1150 | # segsize, so it guesses wrong and must do extra roundtrips. |
---|
1151 | u = upload.Data(plaintext, None) |
---|
1152 | u.max_segment_size = 120 # 3 segs, 4-wide hashtree |
---|
1153 | |
---|
1154 | d = self.c0.upload(u) |
---|
1155 | def _uploaded(ur): |
---|
1156 | imm_uri = ur.get_uri() |
---|
1157 | self.shares = self.copy_shares(imm_uri) |
---|
1158 | |
---|
1159 | corrupt_me = [(48, "block data", "Last failure: None"), |
---|
1160 | (600+2*32, "block_hashes[2]", "BadHashError"), |
---|
1161 | (376+2*32, "crypttext_hash_tree[2]", "BadHashError"), |
---|
1162 | (824, "share_hashes", "BadHashError"), |
---|
1163 | ] |
---|
1164 | def _download(imm_uri): |
---|
1165 | n = self.c0.create_node_from_uri(imm_uri) |
---|
1166 | n._cnode._maybe_create_download_node() |
---|
1167 | # for this test to work, we need to have a new Node each time. |
---|
1168 | # Make sure the NodeMaker's weakcache hasn't interfered. |
---|
1169 | assert not n._cnode._node._shares |
---|
1170 | return download_to_data(n) |
---|
1171 | |
---|
1172 | d = defer.succeed(None) |
---|
1173 | for i,which,substring in corrupt_me: |
---|
1174 | # All these tests result in a failed download. |
---|
1175 | d.addCallback(self._corrupt_flip_all, imm_uri, i) |
---|
1176 | d.addCallback(lambda ign, which=which, substring=substring: |
---|
1177 | self.shouldFail(NoSharesError, which, |
---|
1178 | substring, |
---|
1179 | _download, imm_uri)) |
---|
1180 | d.addCallback(lambda ign: self.restore_all_shares(self.shares)) |
---|
1181 | d.addCallback(fireEventually) |
---|
1182 | return d |
---|
1183 | d.addCallback(_uploaded) |
---|
1184 | |
---|
1185 | return d |
---|
1186 | |
---|
1187 | def _corrupt_flip_all(self, ign: Any, imm_uri: bytes, which: int) -> None: |
---|
1188 | """ |
---|
1189 | Flip the least significant bit at a given byte position in all share files |
---|
1190 | for the given capability. |
---|
1191 | """ |
---|
1192 | def _corruptor(s, debug=False): |
---|
1193 | # type: (bytes, bool) -> bytes |
---|
1194 | before_corruption = s[:which] |
---|
1195 | after_corruption = s[which+1:] |
---|
1196 | original_byte = s[which:which+1] |
---|
1197 | corrupt_byte = bchr(ord(original_byte) ^ 0x01) |
---|
1198 | return b"".join([before_corruption, corrupt_byte, after_corruption]) |
---|
1199 | self.corrupt_all_shares(imm_uri, _corruptor) |
---|
1200 | |
---|
1201 | class DownloadV2(_Base, unittest.TestCase): |
---|
1202 | # tests which exercise v2-share code. They first upload a file with |
---|
1203 | # FORCE_V2 set. |
---|
1204 | |
---|
1205 | def setUp(self): |
---|
1206 | d = defer.maybeDeferred(_Base.setUp, self) |
---|
1207 | def _set_force_v2(ign): |
---|
1208 | self.old_force_v2 = layout.FORCE_V2 |
---|
1209 | layout.FORCE_V2 = True |
---|
1210 | d.addCallback(_set_force_v2) |
---|
1211 | return d |
---|
1212 | def tearDown(self): |
---|
1213 | layout.FORCE_V2 = self.old_force_v2 |
---|
1214 | return _Base.tearDown(self) |
---|
1215 | |
---|
1216 | def test_download(self): |
---|
1217 | self.basedir = self.mktemp() |
---|
1218 | self.set_up_grid() |
---|
1219 | self.c0 = self.g.clients[0] |
---|
1220 | |
---|
1221 | # upload a file |
---|
1222 | u = upload.Data(plaintext, None) |
---|
1223 | d = self.c0.upload(u) |
---|
1224 | def _uploaded(ur): |
---|
1225 | imm_uri = ur.get_uri() |
---|
1226 | n = self.c0.create_node_from_uri(imm_uri) |
---|
1227 | return download_to_data(n) |
---|
1228 | d.addCallback(_uploaded) |
---|
1229 | return d |
---|
1230 | |
---|
1231 | def test_download_no_overrun(self): |
---|
1232 | self.basedir = self.mktemp() |
---|
1233 | self.set_up_grid() |
---|
1234 | self.c0 = self.g.clients[0] |
---|
1235 | |
---|
1236 | # tweak the client's copies of server-version data, so it believes |
---|
1237 | # that they're old and can't handle reads that overrun the length of |
---|
1238 | # the share. This exercises a different code path. |
---|
1239 | for s in self.c0.storage_broker.get_connected_servers(): |
---|
1240 | v = s.get_version() |
---|
1241 | v1 = v[b"http://allmydata.org/tahoe/protocols/storage/v1"] |
---|
1242 | v1[b"tolerates-immutable-read-overrun"] = False |
---|
1243 | |
---|
1244 | # upload a file |
---|
1245 | u = upload.Data(plaintext, None) |
---|
1246 | d = self.c0.upload(u) |
---|
1247 | def _uploaded(ur): |
---|
1248 | imm_uri = ur.get_uri() |
---|
1249 | n = self.c0.create_node_from_uri(imm_uri) |
---|
1250 | return download_to_data(n) |
---|
1251 | d.addCallback(_uploaded) |
---|
1252 | return d |
---|
1253 | |
---|
1254 | def OFF_test_no_overrun_corrupt_shver(self): # unnecessary |
---|
1255 | self.basedir = self.mktemp() |
---|
1256 | self.set_up_grid() |
---|
1257 | self.c0 = self.g.clients[0] |
---|
1258 | |
---|
1259 | for s in self.c0.storage_broker.get_connected_servers(): |
---|
1260 | v = s.get_version() |
---|
1261 | v1 = v["http://allmydata.org/tahoe/protocols/storage/v1"] |
---|
1262 | v1["tolerates-immutable-read-overrun"] = False |
---|
1263 | |
---|
1264 | # upload a file |
---|
1265 | u = upload.Data(plaintext, None) |
---|
1266 | d = self.c0.upload(u) |
---|
1267 | def _uploaded(ur): |
---|
1268 | imm_uri = ur.get_uri() |
---|
1269 | def _do_corrupt(which, newvalue): |
---|
1270 | def _corruptor(s, debug=False): |
---|
1271 | return s[:which] + chr(newvalue) + s[which+1:] |
---|
1272 | self.corrupt_shares_numbered(imm_uri, [0], _corruptor) |
---|
1273 | _do_corrupt(12+3, 0x00) |
---|
1274 | n = self.c0.create_node_from_uri(imm_uri) |
---|
1275 | d = download_to_data(n) |
---|
1276 | def _got_data(data): |
---|
1277 | self.failUnlessEqual(data, plaintext) |
---|
1278 | d.addCallback(_got_data) |
---|
1279 | return d |
---|
1280 | d.addCallback(_uploaded) |
---|
1281 | return d |
---|
1282 | |
---|
1283 | class Status(unittest.TestCase): |
---|
1284 | def test_status(self): |
---|
1285 | now = 12345.1 |
---|
1286 | ds = DownloadStatus("si-1", 123) |
---|
1287 | self.failUnlessEqual(ds.get_status(), "idle") |
---|
1288 | ev0 = ds.add_segment_request(0, now) |
---|
1289 | self.failUnlessEqual(ds.get_status(), "fetching segment 0") |
---|
1290 | ev0.activate(now+0.5) |
---|
1291 | ev0.deliver(now+1, 0, 1000, 2.0) |
---|
1292 | self.failUnlessEqual(ds.get_status(), "idle") |
---|
1293 | ev2 = ds.add_segment_request(2, now+2) |
---|
1294 | del ev2 # hush pyflakes |
---|
1295 | ev1 = ds.add_segment_request(1, now+2) |
---|
1296 | self.failUnlessEqual(ds.get_status(), "fetching segments 1,2") |
---|
1297 | ev1.error(now+3) |
---|
1298 | self.failUnlessEqual(ds.get_status(), |
---|
1299 | "fetching segment 2; errors on segment 1") |
---|
1300 | |
---|
1301 | def test_progress(self): |
---|
1302 | now = 12345.1 |
---|
1303 | ds = DownloadStatus("si-1", 123) |
---|
1304 | self.failUnlessEqual(ds.get_progress(), 0.0) |
---|
1305 | e = ds.add_read_event(0, 1000, now) |
---|
1306 | self.failUnlessEqual(ds.get_progress(), 0.0) |
---|
1307 | e.update(500, 2.0, 2.0) |
---|
1308 | self.failUnlessEqual(ds.get_progress(), 0.5) |
---|
1309 | e.finished(now+2) |
---|
1310 | self.failUnlessEqual(ds.get_progress(), 1.0) |
---|
1311 | |
---|
1312 | e1 = ds.add_read_event(1000, 2000, now+3) |
---|
1313 | e2 = ds.add_read_event(4000, 2000, now+3) |
---|
1314 | self.failUnlessEqual(ds.get_progress(), 0.0) |
---|
1315 | e1.update(1000, 2.0, 2.0) |
---|
1316 | self.failUnlessEqual(ds.get_progress(), 0.25) |
---|
1317 | e2.update(1000, 2.0, 2.0) |
---|
1318 | self.failUnlessEqual(ds.get_progress(), 0.5) |
---|
1319 | e1.update(1000, 2.0, 2.0) |
---|
1320 | e1.finished(now+4) |
---|
1321 | # now there is only one outstanding read, and it is 50% done |
---|
1322 | self.failUnlessEqual(ds.get_progress(), 0.5) |
---|
1323 | e2.update(1000, 2.0, 2.0) |
---|
1324 | e2.finished(now+5) |
---|
1325 | self.failUnlessEqual(ds.get_progress(), 1.0) |
---|
1326 | |
---|
1327 | def test_active(self): |
---|
1328 | now = 12345.1 |
---|
1329 | ds = DownloadStatus("si-1", 123) |
---|
1330 | self.failUnlessEqual(ds.get_active(), False) |
---|
1331 | e1 = ds.add_read_event(0, 1000, now) |
---|
1332 | self.failUnlessEqual(ds.get_active(), True) |
---|
1333 | e2 = ds.add_read_event(1, 1000, now+1) |
---|
1334 | self.failUnlessEqual(ds.get_active(), True) |
---|
1335 | e1.finished(now+2) |
---|
1336 | self.failUnlessEqual(ds.get_active(), True) |
---|
1337 | e2.finished(now+3) |
---|
1338 | self.failUnlessEqual(ds.get_active(), False) |
---|
1339 | |
---|
1340 | def make_server(clientid): |
---|
1341 | tubid = hashutil.tagged_hash(b"clientid", clientid)[:20] |
---|
1342 | return NoNetworkServer(tubid, None) |
---|
1343 | def make_servers(clientids): |
---|
1344 | servers = {} |
---|
1345 | for clientid in clientids: |
---|
1346 | servers[clientid] = make_server(clientid) |
---|
1347 | return servers |
---|
1348 | |
---|
1349 | class MyShare(object): |
---|
1350 | def __init__(self, shnum, server, rtt): |
---|
1351 | self._shnum = shnum |
---|
1352 | self._server = server |
---|
1353 | self._dyhb_rtt = rtt |
---|
1354 | |
---|
1355 | def __repr__(self): |
---|
1356 | return "sh%d-on-%s" % (self._shnum, str(self._server.get_name(), "ascii")) |
---|
1357 | |
---|
1358 | class MySegmentFetcher(SegmentFetcher): |
---|
1359 | def __init__(self, *args, **kwargs): |
---|
1360 | SegmentFetcher.__init__(self, *args, **kwargs) |
---|
1361 | self._test_start_shares = [] |
---|
1362 | def _start_share(self, share, shnum): |
---|
1363 | self._test_start_shares.append(share) |
---|
1364 | |
---|
1365 | class FakeNode(object): |
---|
1366 | def __init__(self): |
---|
1367 | self.want_more = 0 |
---|
1368 | self.failed = None |
---|
1369 | self.processed = None |
---|
1370 | self._si_prefix = "si_prefix" |
---|
1371 | |
---|
1372 | def want_more_shares(self): |
---|
1373 | self.want_more += 1 |
---|
1374 | |
---|
1375 | def fetch_failed(self, fetcher, f): |
---|
1376 | self.failed = f |
---|
1377 | |
---|
1378 | def process_blocks(self, segnum, blocks): |
---|
1379 | self.processed = (segnum, blocks) |
---|
1380 | |
---|
1381 | def get_num_segments(self): |
---|
1382 | return 1, True |
---|
1383 | |
---|
1384 | |
---|
1385 | class Selection(unittest.TestCase): |
---|
1386 | def test_failure(self): |
---|
1387 | """If the fetch loop fails, it tell the Node the fetch failed.""" |
---|
1388 | node = FakeNode() |
---|
1389 | # Simulate a failure: |
---|
1390 | node.get_num_segments = lambda: 1/0 |
---|
1391 | sf = SegmentFetcher(node, 0, 3, None) |
---|
1392 | sf.add_shares([]) |
---|
1393 | d = flushEventualQueue() |
---|
1394 | def _check1(ign): |
---|
1395 | [_] = self.flushLoggedErrors(ZeroDivisionError) |
---|
1396 | self.failUnless(node.failed) |
---|
1397 | self.failUnless(node.failed.check(ZeroDivisionError)) |
---|
1398 | d.addCallback(_check1) |
---|
1399 | return d |
---|
1400 | |
---|
1401 | def test_no_shares(self): |
---|
1402 | node = FakeNode() |
---|
1403 | sf = SegmentFetcher(node, 0, 3, None) |
---|
1404 | sf.add_shares([]) |
---|
1405 | d = flushEventualQueue() |
---|
1406 | def _check1(ign): |
---|
1407 | self.failUnlessEqual(node.want_more, 1) |
---|
1408 | self.failUnlessEqual(node.failed, None) |
---|
1409 | sf.no_more_shares() |
---|
1410 | return flushEventualQueue() |
---|
1411 | d.addCallback(_check1) |
---|
1412 | def _check2(ign): |
---|
1413 | self.failUnless(node.failed) |
---|
1414 | self.failUnless(node.failed.check(NoSharesError)) |
---|
1415 | d.addCallback(_check2) |
---|
1416 | return d |
---|
1417 | |
---|
1418 | def test_only_one_share(self): |
---|
1419 | node = FakeNode() |
---|
1420 | sf = MySegmentFetcher(node, 0, 3, None) |
---|
1421 | serverA = make_server(b"peer-A") |
---|
1422 | shares = [MyShare(0, serverA, 0.0)] |
---|
1423 | sf.add_shares(shares) |
---|
1424 | d = flushEventualQueue() |
---|
1425 | def _check1(ign): |
---|
1426 | self.failUnlessEqual(node.want_more, 1) |
---|
1427 | self.failUnlessEqual(node.failed, None) |
---|
1428 | sf.no_more_shares() |
---|
1429 | return flushEventualQueue() |
---|
1430 | d.addCallback(_check1) |
---|
1431 | def _check2(ign): |
---|
1432 | self.failUnless(node.failed) |
---|
1433 | self.failUnless(node.failed.check(NotEnoughSharesError)) |
---|
1434 | sname = serverA.get_name() |
---|
1435 | self.failUnlessIn("complete= pending=sh0-on-%s overdue= unused=" % str(sname, "ascii"), |
---|
1436 | str(node.failed)) |
---|
1437 | d.addCallback(_check2) |
---|
1438 | return d |
---|
1439 | |
---|
1440 | def test_good_diversity_early(self): |
---|
1441 | node = FakeNode() |
---|
1442 | sf = MySegmentFetcher(node, 0, 3, None) |
---|
1443 | shares = [MyShare(i, make_server(b"peer-%d" % i), i) for i in range(10)] |
---|
1444 | sf.add_shares(shares) |
---|
1445 | d = flushEventualQueue() |
---|
1446 | def _check1(ign): |
---|
1447 | self.failUnlessEqual(node.want_more, 0) |
---|
1448 | self.failUnlessEqual(sf._test_start_shares, shares[:3]) |
---|
1449 | for sh in sf._test_start_shares: |
---|
1450 | sf._block_request_activity(sh, sh._shnum, COMPLETE, |
---|
1451 | "block-%d" % sh._shnum) |
---|
1452 | return flushEventualQueue() |
---|
1453 | d.addCallback(_check1) |
---|
1454 | def _check2(ign): |
---|
1455 | self.failIfEqual(node.processed, None) |
---|
1456 | self.failUnlessEqual(node.processed, (0, {0: "block-0", |
---|
1457 | 1: "block-1", |
---|
1458 | 2: "block-2"}) ) |
---|
1459 | d.addCallback(_check2) |
---|
1460 | return d |
---|
1461 | |
---|
1462 | def test_good_diversity_late(self): |
---|
1463 | node = FakeNode() |
---|
1464 | sf = MySegmentFetcher(node, 0, 3, None) |
---|
1465 | shares = [MyShare(i, make_server(b"peer-%d" % i), i) for i in range(10)] |
---|
1466 | sf.add_shares([]) |
---|
1467 | d = flushEventualQueue() |
---|
1468 | def _check1(ign): |
---|
1469 | self.failUnlessEqual(node.want_more, 1) |
---|
1470 | sf.add_shares(shares) |
---|
1471 | return flushEventualQueue() |
---|
1472 | d.addCallback(_check1) |
---|
1473 | def _check2(ign): |
---|
1474 | self.failUnlessEqual(sf._test_start_shares, shares[:3]) |
---|
1475 | for sh in sf._test_start_shares: |
---|
1476 | sf._block_request_activity(sh, sh._shnum, COMPLETE, |
---|
1477 | "block-%d" % sh._shnum) |
---|
1478 | return flushEventualQueue() |
---|
1479 | d.addCallback(_check2) |
---|
1480 | def _check3(ign): |
---|
1481 | self.failIfEqual(node.processed, None) |
---|
1482 | self.failUnlessEqual(node.processed, (0, {0: "block-0", |
---|
1483 | 1: "block-1", |
---|
1484 | 2: "block-2"}) ) |
---|
1485 | d.addCallback(_check3) |
---|
1486 | return d |
---|
1487 | |
---|
1488 | def test_avoid_bad_diversity_late(self): |
---|
1489 | node = FakeNode() |
---|
1490 | sf = MySegmentFetcher(node, 0, 3, None) |
---|
1491 | # we could satisfy the read entirely from the first server, but we'd |
---|
1492 | # prefer not to. Instead, we expect to only pull one share from the |
---|
1493 | # first server |
---|
1494 | servers = make_servers([b"peer-A", b"peer-B", b"peer-C"]) |
---|
1495 | shares = [MyShare(0, servers[b"peer-A"], 0.0), |
---|
1496 | MyShare(1, servers[b"peer-A"], 0.0), |
---|
1497 | MyShare(2, servers[b"peer-A"], 0.0), |
---|
1498 | MyShare(3, servers[b"peer-B"], 1.0), |
---|
1499 | MyShare(4, servers[b"peer-C"], 2.0), |
---|
1500 | ] |
---|
1501 | sf.add_shares([]) |
---|
1502 | d = flushEventualQueue() |
---|
1503 | def _check1(ign): |
---|
1504 | self.failUnlessEqual(node.want_more, 1) |
---|
1505 | sf.add_shares(shares) |
---|
1506 | return flushEventualQueue() |
---|
1507 | d.addCallback(_check1) |
---|
1508 | def _check2(ign): |
---|
1509 | self.failUnlessEqual(sf._test_start_shares, |
---|
1510 | [shares[0], shares[3], shares[4]]) |
---|
1511 | for sh in sf._test_start_shares: |
---|
1512 | sf._block_request_activity(sh, sh._shnum, COMPLETE, |
---|
1513 | "block-%d" % sh._shnum) |
---|
1514 | return flushEventualQueue() |
---|
1515 | d.addCallback(_check2) |
---|
1516 | def _check3(ign): |
---|
1517 | self.failIfEqual(node.processed, None) |
---|
1518 | self.failUnlessEqual(node.processed, (0, {0: "block-0", |
---|
1519 | 3: "block-3", |
---|
1520 | 4: "block-4"}) ) |
---|
1521 | d.addCallback(_check3) |
---|
1522 | return d |
---|
1523 | |
---|
1524 | def test_suffer_bad_diversity_late(self): |
---|
1525 | node = FakeNode() |
---|
1526 | sf = MySegmentFetcher(node, 0, 3, None) |
---|
1527 | # we satisfy the read entirely from the first server because we don't |
---|
1528 | # have any other choice. |
---|
1529 | serverA = make_server(b"peer-A") |
---|
1530 | shares = [MyShare(0, serverA, 0.0), |
---|
1531 | MyShare(1, serverA, 0.0), |
---|
1532 | MyShare(2, serverA, 0.0), |
---|
1533 | MyShare(3, serverA, 0.0), |
---|
1534 | MyShare(4, serverA, 0.0), |
---|
1535 | ] |
---|
1536 | sf.add_shares([]) |
---|
1537 | d = flushEventualQueue() |
---|
1538 | def _check1(ign): |
---|
1539 | self.failUnlessEqual(node.want_more, 1) |
---|
1540 | sf.add_shares(shares) |
---|
1541 | return flushEventualQueue() |
---|
1542 | d.addCallback(_check1) |
---|
1543 | def _check2(ign): |
---|
1544 | self.failUnlessEqual(node.want_more, 3) |
---|
1545 | self.failUnlessEqual(sf._test_start_shares, |
---|
1546 | [shares[0], shares[1], shares[2]]) |
---|
1547 | for sh in sf._test_start_shares: |
---|
1548 | sf._block_request_activity(sh, sh._shnum, COMPLETE, |
---|
1549 | "block-%d" % sh._shnum) |
---|
1550 | return flushEventualQueue() |
---|
1551 | d.addCallback(_check2) |
---|
1552 | def _check3(ign): |
---|
1553 | self.failIfEqual(node.processed, None) |
---|
1554 | self.failUnlessEqual(node.processed, (0, {0: "block-0", |
---|
1555 | 1: "block-1", |
---|
1556 | 2: "block-2"}) ) |
---|
1557 | d.addCallback(_check3) |
---|
1558 | return d |
---|
1559 | |
---|
1560 | def test_suffer_bad_diversity_early(self): |
---|
1561 | node = FakeNode() |
---|
1562 | sf = MySegmentFetcher(node, 0, 3, None) |
---|
1563 | # we satisfy the read entirely from the first server because we don't |
---|
1564 | # have any other choice. |
---|
1565 | serverA = make_server(b"peer-A") |
---|
1566 | shares = [MyShare(0, serverA, 0.0), |
---|
1567 | MyShare(1, serverA, 0.0), |
---|
1568 | MyShare(2, serverA, 0.0), |
---|
1569 | MyShare(3, serverA, 0.0), |
---|
1570 | MyShare(4, serverA, 0.0), |
---|
1571 | ] |
---|
1572 | sf.add_shares(shares) |
---|
1573 | d = flushEventualQueue() |
---|
1574 | def _check1(ign): |
---|
1575 | self.failUnlessEqual(node.want_more, 2) |
---|
1576 | self.failUnlessEqual(sf._test_start_shares, |
---|
1577 | [shares[0], shares[1], shares[2]]) |
---|
1578 | for sh in sf._test_start_shares: |
---|
1579 | sf._block_request_activity(sh, sh._shnum, COMPLETE, |
---|
1580 | "block-%d" % sh._shnum) |
---|
1581 | return flushEventualQueue() |
---|
1582 | d.addCallback(_check1) |
---|
1583 | def _check2(ign): |
---|
1584 | self.failIfEqual(node.processed, None) |
---|
1585 | self.failUnlessEqual(node.processed, (0, {0: "block-0", |
---|
1586 | 1: "block-1", |
---|
1587 | 2: "block-2"}) ) |
---|
1588 | d.addCallback(_check2) |
---|
1589 | return d |
---|
1590 | |
---|
1591 | def test_overdue(self): |
---|
1592 | node = FakeNode() |
---|
1593 | sf = MySegmentFetcher(node, 0, 3, None) |
---|
1594 | shares = [MyShare(i, make_server(b"peer-%d" % i), i) for i in range(10)] |
---|
1595 | sf.add_shares(shares) |
---|
1596 | d = flushEventualQueue() |
---|
1597 | def _check1(ign): |
---|
1598 | self.failUnlessEqual(node.want_more, 0) |
---|
1599 | self.failUnlessEqual(sf._test_start_shares, shares[:3]) |
---|
1600 | for sh in sf._test_start_shares: |
---|
1601 | sf._block_request_activity(sh, sh._shnum, OVERDUE) |
---|
1602 | return flushEventualQueue() |
---|
1603 | d.addCallback(_check1) |
---|
1604 | def _check2(ign): |
---|
1605 | self.failUnlessEqual(sf._test_start_shares, shares[:6]) |
---|
1606 | for sh in sf._test_start_shares[3:]: |
---|
1607 | sf._block_request_activity(sh, sh._shnum, COMPLETE, |
---|
1608 | "block-%d" % sh._shnum) |
---|
1609 | return flushEventualQueue() |
---|
1610 | d.addCallback(_check2) |
---|
1611 | def _check3(ign): |
---|
1612 | self.failIfEqual(node.processed, None) |
---|
1613 | self.failUnlessEqual(node.processed, (0, {3: "block-3", |
---|
1614 | 4: "block-4", |
---|
1615 | 5: "block-5"}) ) |
---|
1616 | d.addCallback(_check3) |
---|
1617 | return d |
---|
1618 | |
---|
1619 | def test_overdue_fails(self): |
---|
1620 | node = FakeNode() |
---|
1621 | sf = MySegmentFetcher(node, 0, 3, None) |
---|
1622 | servers = make_servers([b"peer-%d" % i for i in range(6)]) |
---|
1623 | shares = [MyShare(i, servers[b"peer-%d" % i], i) for i in range(6)] |
---|
1624 | sf.add_shares(shares) |
---|
1625 | sf.no_more_shares() |
---|
1626 | d = flushEventualQueue() |
---|
1627 | def _check1(ign): |
---|
1628 | self.failUnlessEqual(node.want_more, 0) |
---|
1629 | self.failUnlessEqual(sf._test_start_shares, shares[:3]) |
---|
1630 | for sh in sf._test_start_shares: |
---|
1631 | sf._block_request_activity(sh, sh._shnum, OVERDUE) |
---|
1632 | return flushEventualQueue() |
---|
1633 | d.addCallback(_check1) |
---|
1634 | def _check2(ign): |
---|
1635 | self.failUnlessEqual(sf._test_start_shares, shares[:6]) |
---|
1636 | for sh in sf._test_start_shares[3:]: |
---|
1637 | sf._block_request_activity(sh, sh._shnum, DEAD) |
---|
1638 | return flushEventualQueue() |
---|
1639 | d.addCallback(_check2) |
---|
1640 | def _check3(ign): |
---|
1641 | # we're still waiting |
---|
1642 | self.failUnlessEqual(node.processed, None) |
---|
1643 | self.failUnlessEqual(node.failed, None) |
---|
1644 | # now complete one of the overdue ones, and kill one of the other |
---|
1645 | # ones, leaving one hanging. This should trigger a failure, since |
---|
1646 | # we cannot succeed. |
---|
1647 | live = sf._test_start_shares[0] |
---|
1648 | die = sf._test_start_shares[1] |
---|
1649 | sf._block_request_activity(live, live._shnum, COMPLETE, "block") |
---|
1650 | sf._block_request_activity(die, die._shnum, DEAD) |
---|
1651 | return flushEventualQueue() |
---|
1652 | d.addCallback(_check3) |
---|
1653 | def _check4(ign): |
---|
1654 | self.failUnless(node.failed) |
---|
1655 | self.failUnless(node.failed.check(NotEnoughSharesError)) |
---|
1656 | sname = servers[b"peer-2"].get_name() |
---|
1657 | self.failUnlessIn("complete=sh0 pending= overdue=sh2-on-%s unused=" % str(sname, "ascii"), |
---|
1658 | str(node.failed)) |
---|
1659 | d.addCallback(_check4) |
---|
1660 | return d |
---|
1661 | |
---|
1662 | def test_avoid_redundancy(self): |
---|
1663 | node = FakeNode() |
---|
1664 | sf = MySegmentFetcher(node, 0, 3, None) |
---|
1665 | # we could satisfy the read entirely from the first server, but we'd |
---|
1666 | # prefer not to. Instead, we expect to only pull one share from the |
---|
1667 | # first server |
---|
1668 | servers = make_servers([b"peer-A", b"peer-B", b"peer-C", b"peer-D", |
---|
1669 | b"peer-E"]) |
---|
1670 | shares = [MyShare(0, servers[b"peer-A"],0.0), |
---|
1671 | MyShare(1, servers[b"peer-B"],1.0), |
---|
1672 | MyShare(0, servers[b"peer-C"],2.0), # this will be skipped |
---|
1673 | MyShare(1, servers[b"peer-D"],3.0), |
---|
1674 | MyShare(2, servers[b"peer-E"],4.0), |
---|
1675 | ] |
---|
1676 | sf.add_shares(shares[:3]) |
---|
1677 | d = flushEventualQueue() |
---|
1678 | def _check1(ign): |
---|
1679 | self.failUnlessEqual(node.want_more, 1) |
---|
1680 | self.failUnlessEqual(sf._test_start_shares, |
---|
1681 | [shares[0], shares[1]]) |
---|
1682 | # allow sh1 to retire |
---|
1683 | sf._block_request_activity(shares[1], 1, COMPLETE, "block-1") |
---|
1684 | return flushEventualQueue() |
---|
1685 | d.addCallback(_check1) |
---|
1686 | def _check2(ign): |
---|
1687 | # and then feed in the remaining shares |
---|
1688 | sf.add_shares(shares[3:]) |
---|
1689 | sf.no_more_shares() |
---|
1690 | return flushEventualQueue() |
---|
1691 | d.addCallback(_check2) |
---|
1692 | def _check3(ign): |
---|
1693 | self.failUnlessEqual(sf._test_start_shares, |
---|
1694 | [shares[0], shares[1], shares[4]]) |
---|
1695 | sf._block_request_activity(shares[0], 0, COMPLETE, "block-0") |
---|
1696 | sf._block_request_activity(shares[4], 2, COMPLETE, "block-2") |
---|
1697 | return flushEventualQueue() |
---|
1698 | d.addCallback(_check3) |
---|
1699 | def _check4(ign): |
---|
1700 | self.failIfEqual(node.processed, None) |
---|
1701 | self.failUnlessEqual(node.processed, (0, {0: "block-0", |
---|
1702 | 1: "block-1", |
---|
1703 | 2: "block-2"}) ) |
---|
1704 | d.addCallback(_check4) |
---|
1705 | return d |
---|