def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey, version_bits=blockstack.NAMESPACE_VERSION_PAY_WITH_STACKS) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) # generate 25 names for i in range(0, 25): testlib.blockstack_name_preorder("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) for i in range(0, 25): zonefile_txt = 'hello world {}'.format(i) zonefile_hash = blockstack.lib.storage.get_zonefile_data_hash( zonefile_txt) testlib.blockstack_name_register("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr, zonefile_hash=zonefile_hash) testlib.next_block(**kw) expected_inv = '\x00\x00\x00\x00' assert check_inv(expected_inv) # release zone files according to a pattern r = range(0, 25) random.shuffle(r) for i in r: zonefile_txt = 'hello world {}'.format(i) testlib.blockstack_put_zonefile(zonefile_txt) inv_list = [ord(x) for x in list(expected_inv)] inv_list[i / 8] |= 1 << (7 - (i % 8)) expected_inv = ''.join([chr(x) for x in inv_list]) assert check_inv(expected_inv)
def scenario(wallets, **kw): global working_dir testlib.blockstack_namespace_preorder("id", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "id", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("id", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("judecn.id", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("faker.id", wallets[2].privkey, wallets[4].addr) testlib.next_block(**kw) message = 'hello world!' message_hash = blockstack.lib.storage.get_zonefile_data_hash(message) fake_message = 'This should not appear' fake_message_hash = blockstack.lib.storage.get_zonefile_data_hash( fake_message) testlib.blockstack_name_register("judecn.id", wallets[2].privkey, wallets[3].addr, zonefile_hash=message_hash) testlib.blockstack_name_register("faker.id", wallets[2].privkey, wallets[4].addr, zonefile_hash=fake_message_hash) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(message) assert testlib.blockstack_put_zonefile(fake_message) resp = testlib.blockstack_announce(message, wallets[3].privkey) if 'error' in resp: print json.dumps(resp, indent=4) testlib.next_block(**kw) resp = testlib.blockstack_announce(fake_message, wallets[4].privkey) if 'error' in resp: print json.dumps(resp, indent=4) testlib.next_block(**kw) # save... working_dir = testlib.get_working_dir(**kw)
def scenario( wallets, **kw ): global put_result, legacy_profile, zonefile_hash, zonefile_hash_2, error testlib.blockstack_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey ) testlib.next_block( **kw ) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey ) testlib.next_block( **kw ) testlib.blockstack_namespace_ready( "test", wallets[1].privkey ) testlib.next_block( **kw ) testlib.blockstack_name_preorder( "foo.test", wallets[2].privkey, wallets[3].addr ) testlib.next_block( **kw ) testlib.blockstack_name_register( "foo.test", wallets[2].privkey, wallets[3].addr ) testlib.next_block( **kw ) # give foo.test a nonstandard zonefile (as something that serializes to JSON) nonstandard_zonefile_json = {'nonstandard': 'true', 'error': 'nonstandard'} nonstandard_zonefile_txt = json.dumps(nonstandard_zonefile_json, sort_keys=True) nonstandard_zonefile_raw = binascii.unhexlify( "".join(["%02x" % i for i in xrange(0, 256)])) zf_data = [nonstandard_zonefile_txt, nonstandard_zonefile_raw] for zi in xrange(0, len(zf_data)): nonstandard_zonefile = zf_data[zi] nonstandard_hash = blockstack.lib.storage.get_zonefile_data_hash(zf_data[i]) resp = testlib.blockstack_name_update("foo.test", nonstandard_hash, wallets[3].privkey) if 'error' in resp: print "failed to put nonstandard zonefile '%s'" % nonstandard_zonefile print json.dumps(resp, indent=4, sort_keys=True) return False testlib.next_block(**kw) testlib.blockstack_put_zonefile(nonstandard_zonefile) # getting zonefile should still work... resp = testlib.blockstack_cli_get_name_zonefile( "foo.test") if 'error' in resp: print "failed to get zonefile %s" % zi print json.dumps(resp, indent=4, sort_keys=True) return False if resp != nonstandard_zonefile: print "failed to load nonstandard zonefile json" print "expected:\n%s\n\ngot:\n%s" % (nonstandard_zonefile.encode('hex'), resp.encode('hex')) return False
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo4.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo5.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo6.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo7.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" subdomain_zonefile_pattern = '$ORIGIN {}\n$TTL 3600\n_https._tcp URI 10 1 "https://raw.githubusercontent.com/bar{}/profile.md' zonefiles = { 'foo1.test': make_subdomain_zone_file('foo1.test', 'bar{}.foo1.test', subdomain_zonefile_pattern, 0, 100, 40960, wallets[4].privkey), 'foo2.test': make_subdomain_zone_file('foo2.test', 'bar{}.foo2.test', subdomain_zonefile_pattern, 0, 100, 40960, wallets[4].privkey), 'foo3.test': make_subdomain_zone_file('foo3.test', 'bar{}.foo3.test', subdomain_zonefile_pattern, 0, 100, 40960, wallets[4].privkey) } # register initial subdomains testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.blockstack_name_register("foo4.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register("foo5.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register("foo6.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register("foo7.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # send updates on different names. for i in range(0, 3): zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format( i + 1) name = 'foo{}.test'.format(i + 4) zonefiles = { 'foo1.test': make_subdomain_zone_file(name, 'bar{}.foo1.test', subdomain_zonefile_pattern, i + 1, 100, 40960, wallets[4].privkey), 'foo2.test': make_subdomain_zone_file(name, 'bar{}.foo2.test', subdomain_zonefile_pattern, i + 1, 100, 40960, wallets[4].privkey), 'foo3.test': make_subdomain_zone_file(name, 'bar{}.foo3.test', subdomain_zonefile_pattern, i + 1, 100, 40960, wallets[4].privkey), } testlib.blockstack_name_update( name, storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( name, storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( name, storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # kick off subdomain indexing testlib.next_block(**kw) # query each subdomain for domain in zonefiles: for i in range(0, 100): fqn = 'bar{}.{}'.format(i, domain) res = client.get_name_record(fqn, hostport='http://localhost:16264') if 'error' in res: print res return False # domain should be foo6.test if res['domain'] != 'foo6.test': print 'wrong domain' print res return False expected_zonefile = subdomain_zonefile_pattern.format(fqn, i) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo4.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo5.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo6.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo7.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } # send initial subdomains testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.blockstack_name_register("foo4.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register("foo5.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register("foo6.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register("foo7.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.next_block(**kw) # will send these later initial_zonefiles = zonefiles # send updates too, but all on the same name for i in range(0, 3): zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format( i + 1) name = 'foo{}.test'.format(i + 4) zonefiles = { 'foo1.test': zf_template.format( name, subdomains.make_subdomain_txt( 'bar.foo1.test', name, wallets[4].addr, i + 1, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( name, subdomains.make_subdomain_txt( 'bar.foo2.test', name, wallets[4].addr, i + 1, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( name, subdomains.make_subdomain_txt( 'bar.foo3.test', name, wallets[4].addr, i + 1, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_update( name, storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( name, storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( name, storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # kick off subdomain indexing (nothing should happen) testlib.next_block(**kw) # send initial zonefiles assert testlib.blockstack_put_zonefile(initial_zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(initial_zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(initial_zonefiles['foo3.test']) # now kick it off again testlib.next_block(**kw) # query each subdomain proxy = testlib.make_proxy() for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, proxy=proxy) if 'error' in res: print res return False expected_zonefile = zf_template.format(fqn, zf_default_url) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo4.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo5.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo6.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo7.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.blockstack_name_register("foo4.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_register("foo5.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_register("foo6.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_register("foo7.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # kick off indexing and check testlib.next_block(**kw) def _query_subdomains(subdomain_names, expected_sequence, expected_owner, expect_pending): # query each subdomain. Should get the latest proxy = testlib.make_proxy() for fqn in subdomain_names: res = client.get_name_record(fqn, proxy=proxy) if 'error' in res: print res print 'failed to query {}'.format(fqn) return False # should have right sequence if res['sequence'] != expected_sequence: print 'wrong sequence; expected {}'.format(expected_sequence) print res return False # should have right owner if res['address'] != expected_owner: print 'wrong owner' print 'expected {}'.format(res['address']) print res return False # do we expect pending? if res['pending'] != expect_pending: print 'wrong pending (expected {})'.format(expect_pending) print res return False return True assert _query_subdomains( ['bar.foo1.test', 'bar.foo2.test', 'bar.foo3.test'], 0, wallets[4].addr, False) expected_owners_before = [wallets[4].addr] expected_owners_after = [wallets[4].addr] # update and transfer, but if i % 2 == 0, transfer to a different address # use a different domain name in each case. # verify that only transfers on the creator domain are valid. wallet_schedule = [ (4, 0), # not broadcast initially (4, 1), (0, 1), # not broadcast initially (1, 2), ] sequence_schedule = [ 1, 1, 2, 2, ] expected_zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format( 4) expect_pending = False expect_sequence = 0 expect_owner = wallets[4].addr unsent_zonefiles = [] # send updates too, and transfer subdomains for i in range(0, 4): zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format( i + 1) names = [ 'foo1.test', 'foo2.test', 'foo3.test', ] k = wallet_schedule[i][0] k2 = wallet_schedule[i][1] s = sequence_schedule[i] zonefiles = { 'foo1.test': zf_template.format( names[0], subdomains.make_subdomain_txt( 'bar.foo1.test', names[0], wallets[k2].addr, s, zf_template.format('bar.foo1.test', zf_default_url), wallets[k].privkey)), 'foo2.test': zf_template.format( names[1], subdomains.make_subdomain_txt( 'bar.foo2.test', names[1], wallets[k2].addr, s, zf_template.format('bar.foo2.test', zf_default_url), wallets[k].privkey)), 'foo3.test': zf_template.format( names[2], subdomains.make_subdomain_txt( 'bar.foo3.test', names[2], wallets[k2].addr, s, zf_template.format('bar.foo3.test', zf_default_url), wallets[k].privkey)), } testlib.blockstack_name_update( names[0], storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( names[1], storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( names[2], storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) if i % 2 == 1: # only broadcast periodically assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) expect_owner = wallets[k2].addr expect_sequence += 1 expected_owners_before.append(expect_owner) else: expect_pending = True unsent_zonefiles.append(zonefiles) expected_owners_after.append(wallets[k2].addr) # kick off subdomain indexing testlib.next_block(**kw) # verify history assert _query_subdomains( ['bar.foo1.test', 'bar.foo2.test', 'bar.foo3.test'], expect_sequence, expect_owner, expect_pending) # query subdomain history proxy = testlib.make_proxy() for subd in ['bar.foo1.test', 'bar.foo2.test', 'bar.foo3.test']: res = client.get_name_record(subd, include_history=True, proxy=proxy) if 'error' in res: print res return False if not res['pending']: print 'not pending, but it should be' print res return False # should be at 2 if res['sequence'] != 2: print 'wrong sequence' print res return False if virtualchain.address_reencode(str( res['address'])) != virtualchain.address_reencode( expect_owner): print 'wrong owner' print res return False for i, block_height in enumerate(sorted(res['history'])): if virtualchain.address_reencode( str(res['history'][block_height][0]['address']) ) != virtualchain.address_reencode(expected_owners_before[i]): print 'wrong owner at {}: expected {}'.format( block_height, expected_owners_before[i]) print json.dumps(res, indent=4, sort_keys=True) print expected_owners_before return False if res['history'][block_height][0]['sequence'] != i: print 'wrong sequence at {}: expected {}'.format( block_height, i) print json.dumps(res, indent=4, sort_keys=True) return False # send all missing subdomains. # should cause a cascading owner reorg. for zfbatch in unsent_zonefiles: for k in zfbatch: assert testlib.blockstack_put_zonefile(zfbatch[k]) testlib.next_block(**kw) # query subdomain history again. pending and owner should change proxy = testlib.make_proxy() for subd in ['bar.foo1.test', 'bar.foo2.test', 'bar.foo3.test']: res = client.get_name_record(subd, include_history=True, proxy=proxy) if 'error' in res: print res return False if res['pending']: print 'pending, but it should not be' print res return False if res['sequence'] != 2: print 'wrong sequence' print res return False if virtualchain.address_reencode(str( res['address'])) != virtualchain.address_reencode( wallets[1].addr): print 'wrong owner again' print res return False for i, block_height in enumerate(sorted(res['history'])): if virtualchain.address_reencode( str(res['history'][block_height][0]['address']) ) != virtualchain.address_reencode(str(expected_owners_after[i])): print 'wrong owner at {}: expected {}'.format( block_height, expected_owners_after[i]) print json.dumps(res, indent=4, sort_keys=True) print expected_owners_after print expected_owners_before print[wallets[i].addr for i in range(0, len(wallets))] return False if res['history'][block_height][0]['sequence'] != i: print 'wrong sequence at {}: expected {}'.format( block_height, i) print json.dumps(res, indent=4, sort_keys=True) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): global synchronized, value_hash import blockstack_integration_tests.atlas_network as atlas_network testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) testlib.blockstack_name_register("foo.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) # register 10 names for i in xrange(0, 10): res = testlib.blockstack_name_preorder("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) for i in xrange(0, 10): res = testlib.blockstack_name_register("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) # make 10 empty zonefiles and propagate them for i in xrange(0, 10): empty_zonefile_str = testlib.make_empty_zonefile( "foo_{}.test".format(i), wallets[3].addr) value_hash = blockstack.lib.storage.get_zonefile_data_hash( empty_zonefile_str) res = testlib.blockstack_name_update("foo_{}.test".format(i), value_hash, wallets[3].privkey) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) res = testlib.blockstack_put_zonefile(empty_zonefile_str) if not res: return False # start up an Atlas test network with 9 nodes: the main one doing the test, and 8 subordinate ones that treat it as a seed peer. # the network will ensure each node can reach each other node. atlas_nodes = [17000, 17001, 17002, 17003, 17004, 17005, 17006, 17007] atlas_topology = {} for node_port in atlas_nodes: atlas_topology[node_port] = [16264] network_des = atlas_network.atlas_network_build( testlib.working_dir(**kw), atlas_nodes, atlas_topology, {}, os.path.join(testlib.working_dir(**kw), "atlas_network")) atlas_network.atlas_network_start(network_des) print "Waiting 60 seconds for the altas peers to catch up" time.sleep(60.0) # wait at most 60 seconds for atlas network to converge synchronized = False for i in xrange(0, 60): atlas_network.atlas_print_network_state(network_des) if atlas_network.atlas_network_is_synchronized( network_des, testlib.last_block(**kw) - 1, 1): print "Synchronized!" synchronized = True break else: time.sleep(1.0) # shut down atlas_network.atlas_network_stop(network_des) return synchronized
def scenario( wallets, **kw ): testlib.blockstack_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey ) testlib.next_block( **kw ) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey ) testlib.next_block( **kw ) testlib.blockstack_namespace_ready( "test", wallets[1].privkey ) testlib.next_block( **kw ) testlib.blockstack_name_preorder( "foo1.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo2.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo3.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo4.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo5.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo6.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo7.test", wallets[2].privkey, wallets[3].addr ) testlib.next_block( **kw ) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' zonefiles = { 'foo1.test': zf_template.format('foo1.test', subdomains.make_subdomain_txt('bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format('foo2.test', subdomains.make_subdomain_txt('bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format('foo3.test', subdomains.make_subdomain_txt('bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.blockstack_name_register( "foo4.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register( "foo5.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register( "foo6.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register( "foo7.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.next_block( **kw ) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # update and transfer, but if i % 2 == 0, transfer to a different address # use a different domain name in each case. # verify that only transfers on the creator domain are valid. wallet_schedule = [ (4, 0), # won't be accepted due to domain independence (4, 1), # will be accepted (1, 2), # won't be accepted due to domain independence (1, 3), # will be accepted ] sequence_schedule = [ 1, # won't be accepted due to domain independence 1, # will be accepted 2, # won't be accepted due to domain independence 2, # will be accepted ] expected_zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format(4) for i in range(0, 4): zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format(i+1) if i % 2 == 0: names = [ 'foo{}.test'.format(i+4), 'foo{}.test'.format(i+4), 'foo{}.test'.format(i+4), ] else: names = [ 'foo1.test', 'foo2.test', 'foo3.test', ] k = wallet_schedule[i][0] k2 = wallet_schedule[i][1] s = sequence_schedule[i] zonefiles = { 'foo1.test': zf_template.format(names[0], subdomains.make_subdomain_txt('bar.foo1.test', names[0], wallets[k2].addr, s, zf_template.format('bar.foo1.test', zf_default_url), wallets[k].privkey)), 'foo2.test': zf_template.format(names[1], subdomains.make_subdomain_txt('bar.foo2.test', names[1], wallets[k2].addr, s, zf_template.format('bar.foo2.test', zf_default_url), wallets[k].privkey)), 'foo3.test': zf_template.format(names[2], subdomains.make_subdomain_txt('bar.foo3.test', names[2], wallets[k2].addr, s, zf_template.format('bar.foo3.test', zf_default_url), wallets[k].privkey)), } testlib.blockstack_name_update(names[0], storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update(names[1], storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update(names[2], storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # kick off subdomain indexing testlib.next_block(**kw) # query each subdomain proxy = testlib.make_proxy() for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, proxy=proxy) if 'error' in res: print res return False if res['sequence'] != 2: print 'wrong sequence' print res return False if virtualchain.address_reencode(str(res['address'])) != virtualchain.address_reencode(wallets[3].addr): print 'wrong owner' print res return False expected_zonefile = zf_template.format(fqn, expected_zf_default_url) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # there should only be three history items per name hist = client.get_name_record(fqn, proxy=proxy, include_history=True) if 'error' in hist: print res return False if len(hist['history']) != 3: print 'wrong history length' print res return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.next_block(**kw) def _query_subdomains(subdomain_names, expected_sequence, expected_owner): # query each subdomain. Should get the latest proxy = testlib.make_proxy() for fqn in subdomain_names: res = client.get_name_record(fqn, proxy=proxy) if 'error' in res: print res print 'failed to query {}'.format(fqn) return False # should have right sequence if res['sequence'] != expected_sequence: print 'wrong sequence; expected {}'.format(expected_sequence) print res return False # should have right owner if res['address'] != expected_owner: print 'wrong owner' print 'expected {}'.format(res['address']) print res return False return True assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # kick off indexing and check testlib.next_block(**kw) assert _query_subdomains( ['bar.foo1.test', 'bar.foo2.test', 'bar.foo3.test'], 0, wallets[4].addr) expected_owners = [wallets[4].addr] # send updates too, and transfer subdomains for i in range(0, 6): zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format( i + 1) j = (4 + i) % 5 k = (4 + i + 1) % 5 expected_owners.append(wallets[k].addr) zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[k].addr, i + 1, zf_template.format('bar.foo1.test', zf_default_url), wallets[j].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[k].addr, i + 1, zf_template.format('bar.foo2.test', zf_default_url), wallets[j].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[k].addr, i + 1, zf_template.format('bar.foo3.test', zf_default_url), wallets[j].privkey)), } testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # kick off subdomain indexing testlib.next_block(**kw) # verify history assert _query_subdomains( ['bar.foo1.test', 'bar.foo2.test', 'bar.foo3.test'], i + 1, wallets[k].addr) # query subdomain history proxy = testlib.make_proxy() for subd in ['bar.foo1.test', 'bar.foo2.test', 'bar.foo3.test']: res = client.get_name_record(subd, include_history=True, proxy=proxy) if 'error' in res: print res return False for i, block_height in enumerate(sorted(res['history'])): if res['history'][block_height][0]['address'] != expected_owners[i]: print 'wrong owner at {}: expected {}'.format( block_height, expected_owners[i]) print json.dumps(res, indent=4, sort_keys=True) return False if res['history'][block_height][0]['sequence'] != i: print 'wrong sequence at {}: expected {}'.format( block_height, i) print json.dumps(res, indent=4, sort_keys=True) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' zf_default_url_initial = zf_default_url zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } initial_zonefiles = zonefiles testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://invalid.com"' zf_default_url_invalid = zf_default_url zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } # send updates for invalid initial subdomain records testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # kick off subdomain indexing. testlib.next_block(**kw) # must all be pending proxy = testlib.make_proxy() for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, proxy=proxy) if not res['pending']: print 'not pending: {}'.format(fqn) print res return False # broadcast initial zonefiles and re-do subdomain indexing assert testlib.blockstack_put_zonefile(initial_zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(initial_zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(initial_zonefiles['foo3.test']) testlib.next_block(**kw) proxy = testlib.make_proxy() for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, proxy=proxy) if 'error' in res: print res return False # right subdomain zonefile expected_zonefile = zf_template.format(fqn, zf_default_url_initial) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) working_dir = testlib.get_working_dir(**kw) sub_zf_template = '$ORIGIN {}\n$TTL 3600\n_http._tcp URI 10 1 "http://www.foo.com"\n{}' zf_template = '$ORIGIN {}\n$TTL 3600\n_http._tcp URI 10 1 "http://www.foo.com"\n_resolver URI 10 1 "http://resolver.foo"\n{}' zf_default_url = '_file URI 10 1 "file://' + working_dir + '/{}"' zf_default_url_2 = '_file URI 20 1 "file://' + working_dir + '/{}"' subdomain_zonefiles = { 'bar.foo1.test': sub_zf_template.format('bar.foo1.test', zf_default_url.format('bar.foo1.test')), 'bar.foo2.test': sub_zf_template.format('bar.foo2.test', zf_default_url.format('bar.foo2.test')), 'bar.foo3.test': sub_zf_template.format('bar.foo3.test', zf_default_url.format('bar.foo3.test')), } zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt('bar.foo1.test', 'foo1.test', wallets[4].addr, 0, subdomain_zonefiles['bar.foo1.test'], wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt('bar.foo2.test', 'foo2.test', wallets[4].addr, 0, subdomain_zonefiles['bar.foo2.test'], wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt('bar.foo3.test', 'foo3.test', wallets[4].addr, 0, subdomain_zonefiles['bar.foo3.test'], wallets[4].privkey)), } testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.next_block(**kw) # sign and put profiles for subd in ['bar.foo1.test', 'bar.foo2.test', 'bar.foo3.test']: profile_data = { 'type': 'Person', 'name': subd, } profile_jwt = testlib.blockstack_make_profile(profile_data, wallets[4].privkey) path = os.path.join(working_dir, subd) with open(path, 'w') as f: f.write(profile_jwt) # whois for i in xrange(1, 4): name = 'foo{}.test'.format(i) res = testlib.blockstack_cli_whois(name) if 'error' in res: print res return False if not res.has_key('zonefile_hash') or res[ 'zonefile_hash'] != storage.get_zonefile_data_hash( zonefiles[name]): print res return False if res['owner_address'] != wallets[3].addr: print res return False # upload zonefile assert testlib.blockstack_put_zonefile(zonefiles[name]) subdomain_zonefiles_2 = { 'bar.foo1.test': zf_template.format('bar.foo1.test', zf_default_url_2.format('bar.foo1.test')), 'bar.foo2.test': zf_template.format('bar.foo2.test', zf_default_url_2.format('bar.foo2.test')), 'bar.foo3.test': zf_template.format('bar.foo3.test', zf_default_url_2.format('bar.foo3.test')), } zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt('bar.foo1.test', 'foo1.test', wallets[4].addr, 1, subdomain_zonefiles['bar.foo1.test'], wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt('bar.foo2.test', 'foo2.test', wallets[4].addr, 1, subdomain_zonefiles['bar.foo2.test'], wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt('bar.foo3.test', 'foo3.test', wallets[4].addr, 1, subdomain_zonefiles['bar.foo3.test'], wallets[4].privkey)), } # update zone files testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # kick off subdomain indexing testlib.next_block(**kw) # start API daemon print 'starting API daemon' wallet_keys = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[0].privkey, wallets[1].privkey, wallets[2].privkey) # authenticate pk = keylib.ECPrivateKey(wallets[-1].privkey).to_hex() res = testlib.blockstack_cli_app_signin("foo.test", pk, 'register.app', [ 'names', 'register', 'prices', 'zonefiles', 'blockchain', 'node_read', 'user_read' ]) if 'error' in res: print json.dumps(res, indent=4, sort_keys=True) error = True return ses = res['token'] # query each subdomain proxy = testlib.make_proxy() # test 301 redirects. res = testlib.blockstack_REST_call('GET', '/v1/names/baz.foo1.test', ses, allow_redirects=False) if 'error' in res: res['test'] = 'Failed to query non-registered name.' print json.dumps(res) return False if res['http_status'] != 301: res['test'] = 'Failed to get a redirect.' print json.dumps(res) return False for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) # test REST whois res = testlib.blockstack_REST_call('GET', '/v1/names/{}'.format(fqn), ses) if 'error' in res: res['test'] = 'Failed to query name' print json.dumps(res) return False if res['http_status'] != 200 and res['http_status'] != 404: res['test'] = 'HTTP status {}, response = {} on name lookup'.format( res['http_status'], res['response']) print json.dumps(res) return False if res['response']['zonefile'] != subdomain_zonefiles[fqn]: print 'wrong zone file' print res print 'expected' print zonefiles['foo{}.test'.format(i)] return False if res['response']['status'] != 'registered_subdomain': print 'wrong status' print res return False # test CLI lookup res = testlib.blockstack_cli_lookup(fqn) if 'error' in res: print res return False print res if res['profile'] != {'type': 'Person', 'name': fqn}: print 'wrong profile' print res['profile'] return False # test REST lookup res = testlib.blockstack_REST_call("GET", "/v1/users/{}".format(fqn), ses) if 'error' in res: res['test'] = 'Failed to query name profile' print json.dumps(res) return False if res['http_status'] != 200 and res['http_status'] != 404: res['test'] = 'HTTP status {}, response = {} on name profile lookup'.format( res['http_status'], res['response']) print json.dumps(res) return False print res if res['response'] != {'type': 'Person', 'name': fqn}: print 'wrong profile on REST call' print res return False # test CLI lookup by address res = testlib.blockstack_cli_get_names_owned_by_address( wallets[4].addr) if 'error' in res: print 'failed to get subdomains owned by {}'.format( wallets[4].addr) print res return False if fqn not in res: print '{} not in list'.format(fqn) print res return False # test REST lookup by address res = testlib.blockstack_REST_call( 'GET', '/v1/addresses/bitcoin/{}'.format(wallets[4].addr), ses) if 'error' in res: res['test'] = 'Failed to query names owned by address' print json.dumps(res) return False if res['http_status'] != 200 and res['http_status'] != 404: res['test'] = 'HTTP status {}, response = {} on address lookup'.format( res['http_status'], res['response']) print json.dumps(res) return False if fqn not in res['response']['names']: print '{} not in REST list'.format(fqn) print res return False # test REST get name history res = testlib.blockstack_REST_call('GET', '/v1/names/{}/history'.format(fqn), ses) if 'error' in res: res['test'] = 'Failed to query subdomain history' print json.dumps(res) return False if res['http_status'] != 200 and res['http_status'] != 404: res['test'] = 'HTTP status {}, response = {} on subdomain history lookup'.format( res['http_status'], res['response']) print json.dumps(res) return False blocks = res['response'] if len(blocks.keys()) != 2: print 'expected two updates' print blocks return False # get each historic zone file for block_height in blocks: for prev_state in blocks[block_height]: value_hash = prev_state['value_hash'] res = testlib.blockstack_REST_call( 'GET', '/v1/names/{}/zonefile/{}'.format(fqn, value_hash), ses) if 'error' in res: print 'failed to query zone file {} for {}'.format( value_hash, fqn) print json.dumps(res) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): start_subdomain_registrar() testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("personal.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) # make an initial subdomain so we record the registrar zf_subdomain_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_subdomain_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' first_subdomain_zf = zf_subdomain_template.format( "first.personal.test", zf_subdomain_default_url) first_subdomain_txt = subdomains.make_subdomain_txt( "first.personal.test", "personal.test", virtualchain.address_reencode(wallets[0].addr, network='mainnet'), 0, first_subdomain_zf, wallets[0].privkey) registrar_zf = '$ORIGIN personal.test\n$TTL 3600\n%s\n_registrar URI 10 1 "http://localhost:%s"\n_resolver URI 10 1 "http://localhost:%s"\n' % ( first_subdomain_txt, registrar_port, registrar_port) registrar_zf_hash = storage.get_zonefile_data_hash(registrar_zf) testlib.blockstack_name_register("personal.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=registrar_zf_hash) testlib.next_block(**kw) testlib.blockstack_put_zonefile(registrar_zf) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' # request to register hello_XXX.personal.test for i in range(0, 50): sub_name = 'hello_{}.personal.test'.format(i) sub_zf = zf_template.format(sub_name, zf_default_url) addr = keylib.b58check_encode('{:040x}'.format( int(keylib.b58check_decode(wallets[0].addr).encode('hex'), 16) + i).decode('hex'), version_byte=0) req_json = { 'name': 'hello_{}'.format(i), 'owner_address': virtualchain.address_reencode(addr, network='mainnet'), 'zonefile': sub_zf, } resp = requests.post( 'http://localhost:{}/register'.format(registrar_port), json=req_json, headers={'Authorization': 'bearer test_registrar'}) if resp.status_code != 202: print 'did not accept {}'.format(sub_name) print resp.text return False # try to resolve each name on the subdomain registrar for i in range(0, 50): sub_name = 'hello_{}'.format(i) resp = requests.get('http://localhost:{}/status/{}'.format( registrar_port, sub_name)) status = resp.json() print json.dumps(status, indent=4, sort_keys=True) if resp.status_code != 200: print 'not accepted: {}'.format(sub_name) return False # test /v1/names/{} emulation on the subdomain registrar for i in range(0, 50): sub_name = 'hello_{}.personal.test'.format(i) resp = requests.get('http://localhost:{}/v1/names/{}'.format( registrar_port, sub_name)) status = resp.json() print json.dumps(status, indent=4, sort_keys=True) if 'pending_subdomain' != status['status']: print 'not pending 1.1: {}'.format(sub_name) return False if len(status['last_txid']) != 0: print 'not pending 1.2: {}'.format(sub_name) return False # test /v1/names/{} redirect from Blockstack Core for i in range(0, 50): sub_name = 'hello_{}.personal.test'.format(i) resp = requests.get('http://localhost:{}/v1/names/{}'.format( 16268, sub_name)) status = resp.json() print json.dumps(status, indent=4, sort_keys=True) if 'pending_subdomain' != status['status']: print 'not pending 2.1: {}'.format(sub_name) return False if len(status['last_txid']) != 0: print 'not pending 2.2: {}'.format(sub_name) return False # tell the registrar to flush the queue resp = requests.post( 'http://localhost:{}/issue_batch/'.format(registrar_port), headers={'Authorization': 'bearer hello_world'}) if resp.status_code >= 300: print 'issue_batch returned {}'.format(resp.status_code) return False print 'wait for subdomain registrar to send the tx' time.sleep(60) testlib.next_block(**kw) testlib.next_block(**kw) testlib.next_block(**kw) testlib.next_block(**kw) testlib.next_block(**kw) testlib.next_block(**kw) testlib.next_block(**kw) # tell the registrar to send the zonefiles resp = requests.post( 'http://localhost:{}/check_zonefiles/'.format(registrar_port), headers={'Authorization': 'bearer hello_world'}) if resp.status_code >= 300: print 'issue_batch returned {}'.format(resp.status_code) return False print 'wait for zonefile to propagate' time.sleep(5) testlib.next_block(**kw) # make sure that /v1/names/{} works without redirect for i in range(0, 3): sub_name = 'hello_{}.personal.test'.format(i) resp = requests.get('http://localhost:{}/v1/names/{}'.format( 16268, sub_name)) if resp.status_code != 200: print 'invalid status code {}'.format(resp.status_code) return False status = resp.json() print json.dumps(status, indent=4, sort_keys=True) if 'registered_subdomain' != status['status']: print 'still pending 3.1: {}'.format(sub_name) return False if len(status['last_txid']) == 0: print 'still pending 2.2: {}'.format(sub_name) return False
def scenario(wallets, **kw): zonefile_batches = [] testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url_0 = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody0/content/profile.md"' zf_default_url_1 = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody1/content/profile.md"' zf_default_url_2 = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody2/content/profile.md"' # initialize with sequence=1 zonefiles_1 = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 1, zf_template.format('bar.foo1.test', zf_default_url_1), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 1, zf_template.format('bar.foo2.test', zf_default_url_1), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 1, zf_template.format('bar.foo3.test', zf_default_url_1), wallets[4].privkey)), } zonefile_batches.append(zonefiles_1) testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles_1['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles_1['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles_1['foo3.test'])) testlib.next_block(**kw) for name in zonefiles_1: assert testlib.blockstack_put_zonefile(zonefiles_1[name]) testlib.next_block(**kw) # send sequence=0 zonefiles_0 = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url_0), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url_0), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url_0), wallets[4].privkey)), } zonefile_batches.append(zonefiles_0) testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles_0['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles_0['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles_0['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) for name in zonefiles_0: assert testlib.blockstack_put_zonefile(zonefiles_0[name]) testlib.next_block(**kw) # all names should now be at sequence 0 # query each subdomain for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, hostport='http://localhost:16264') if 'error' in res: print res return False expected_zonefile = zf_template.format(fqn, zf_default_url_0) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # send sequence=1 hashes again testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles_1['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles_1['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles_1['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) # all names should now be at sequence 1, even though we didn't re-send the zone file # query each subdomain for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, hostport='http://localhost:16264') if 'error' in res: print res return False expected_zonefile = zf_template.format(fqn, zf_default_url_1) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # send sequence=2 zonefiles_2 = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 2, zf_template.format('bar.foo1.test', zf_default_url_2), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 2, zf_template.format('bar.foo2.test', zf_default_url_2), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 2, zf_template.format('bar.foo3.test', zf_default_url_2), wallets[4].privkey)), } zonefile_batches.append(zonefiles_2) testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles_2['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles_2['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles_2['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) for name in zonefiles_2: assert testlib.blockstack_put_zonefile(zonefiles_2[name]) testlib.next_block(**kw) # all names should now be at sequence 2 # query each subdomain for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, hostport='http://localhost:16264') if 'error' in res: print res return False expected_zonefile = zf_template.format(fqn, zf_default_url_2) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): global synchronized, value_hash import blockstack_integration_tests.atlas_network as atlas_network testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) testlib.blockstack_name_register("foo.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) # set up RPC daemon test_proxy = testlib.TestAPIProxy() blockstack_client.set_default_proxy(test_proxy) wallet_keys = blockstack_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[5].privkey) testlib.blockstack_client_set_wallet("0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey']) # register 10 names for i in xrange(0, 10): res = testlib.blockstack_name_preorder("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) for i in xrange(0, 10): res = testlib.blockstack_name_register("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) # make 10 empty zonefiles and propagate them for i in xrange(0, 10): data_pubkey = virtualchain.BitcoinPrivateKey( wallet_keys['data_privkey']).public_key().to_hex() empty_zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo_{}.test".format(i), data_pubkey, urls=["file:///tmp/foo_{}.test".format(i)]) empty_zonefile_str = blockstack_zones.make_zone_file(empty_zonefile) value_hash = blockstack_client.hash_zonefile(empty_zonefile) res = testlib.blockstack_name_update("foo_{}.test".format(i), value_hash, wallets[3].privkey) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) res = testlib.blockstack_put_zonefile(empty_zonefile_str) if not res: return False # start up an Atlas test network with 9 nodes: the main one doing the test, and 8 subordinate ones that treat it as a seed peer. # the network will ensure each node can reach each other node. atlas_nodes = [17000, 17001, 17002, 17003, 17004, 17005, 17006, 17007] atlas_topology = {} for node_port in atlas_nodes: atlas_topology[node_port] = [16264] network_des = atlas_network.atlas_network_build( testlib.working_dir(**kw), atlas_nodes, atlas_topology, {}, os.path.join(testlib.working_dir(**kw), "atlas_network")) atlas_network.atlas_network_start(network_des) print "Waiting 60 seconds for the altas peers to catch up" time.sleep(60.0) # wait at most 60 seconds for atlas network to converge synchronized = False for i in xrange(0, 60): atlas_network.atlas_print_network_state(network_des) if atlas_network.atlas_network_is_synchronized( network_des, testlib.last_block(**kw) - 1, 1): print "Synchronized!" synchronized = True break else: time.sleep(1.0) # shut down atlas_network.atlas_network_stop(network_des) return synchronized
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) working_dir = testlib.get_working_dir(**kw) sub_zf_template = '$ORIGIN {}\n$TTL 3600\n{}' zf_template = '$ORIGIN {}\n$TTL 3600\n_http._tcp URI 10 1 "http://www.foo.com"\n_resolver URI 10 1 "http://resolver.foo"\n{}' zf_default_url = '_file URI 10 1 "http://localhost:4000/hub/{}/profile.json' zf_default_url_2 = '_file URI 20 1 "http://localhost:4000/hub/{}/profile.json' subdomain_zonefiles = { 'bar.foo1.test': sub_zf_template.format( 'bar.foo1.test', zf_default_url.format( virtualchain.address_reencode(wallets[0].addr, network='mainnet'))), 'bar.foo2.test': sub_zf_template.format( 'bar.foo2.test', zf_default_url.format( virtualchain.address_reencode(wallets[1].addr, network='mainnet'))), 'bar.foo3.test': sub_zf_template.format( 'bar.foo3.test', zf_default_url.format( virtualchain.address_reencode(wallets[2].addr, network='mainnet'))), } zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt('bar.foo1.test', 'foo1.test', wallets[0].addr, 0, subdomain_zonefiles['bar.foo1.test'], wallets[0].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt('bar.foo2.test', 'foo2.test', wallets[1].addr, 0, subdomain_zonefiles['bar.foo2.test'], wallets[1].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt('bar.foo3.test', 'foo3.test', wallets[2].addr, 0, subdomain_zonefiles['bar.foo3.test'], wallets[2].privkey)), } testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.next_block(**kw) # sign and put profiles for i, subd in enumerate( ['bar.foo1.test', 'bar.foo2.test', 'bar.foo3.test']): profile_data = { 'type': 'Person', 'name': subd, } profile_jwt = testlib.blockstack_make_profile(profile_data, wallets[i].privkey) testlib.blockstack_put_profile(None, profile_jwt, wallets[i].privkey, 'http://localhost:4000') # whois for i in xrange(1, 4): name = 'foo{}.test'.format(i) res = testlib.blockstack_cli_whois(name) if 'error' in res: print res return False if not res.has_key('zonefile_hash') or res[ 'zonefile_hash'] != storage.get_zonefile_data_hash( zonefiles[name]): print res return False if res['owner_address'] != wallets[3].addr: print res return False # upload zonefile assert testlib.blockstack_put_zonefile(zonefiles[name]) subdomain_zonefiles_2 = { 'bar.foo1.test': sub_zf_template.format( 'bar.foo1.test', zf_default_url_2.format( virtualchain.address_reencode(wallets[0].addr, network='mainnet'))), 'bar.foo2.test': sub_zf_template.format( 'bar.foo2.test', zf_default_url_2.format( virtualchain.address_reencode(wallets[1].addr, network='mainnet'))), 'bar.foo3.test': sub_zf_template.format( 'bar.foo3.test', zf_default_url_2.format( virtualchain.address_reencode(wallets[2].addr, network='mainnet'))), } zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt('bar.foo1.test', 'foo1.test', wallets[0].addr, 1, subdomain_zonefiles['bar.foo1.test'], wallets[0].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt('bar.foo2.test', 'foo2.test', wallets[1].addr, 1, subdomain_zonefiles['bar.foo2.test'], wallets[1].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt('bar.foo3.test', 'foo3.test', wallets[2].addr, 1, subdomain_zonefiles['bar.foo3.test'], wallets[2].privkey)), } # update zone files testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # kick off subdomain indexing testlib.next_block(**kw) # query each subdomain # test 301 redirects. res = testlib.blockstack_REST_call('GET', '/v1/names/baz.foo1.test', allow_redirects=False) if 'error' in res: res['test'] = 'Failed to query non-registered name.' print json.dumps(res) return False if res['http_status'] != 301: res['test'] = 'Failed to get a redirect.' print json.dumps(res) return False for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) # test REST whois res = testlib.blockstack_REST_call('GET', '/v1/names/{}'.format(fqn)) if 'error' in res: res['test'] = 'Failed to query name' print json.dumps(res) return False if res['http_status'] != 200 and res['http_status'] != 404: res['test'] = 'HTTP status {}, response = {} on name lookup'.format( res['http_status'], res['response']) print json.dumps(res) return False if res['response']['zonefile'] != subdomain_zonefiles[fqn]: print 'wrong zone file' print res print 'expected' print zonefiles['foo{}.test'.format(i)] return False if res['response']['status'] != 'registered_subdomain': print 'wrong status' print res return False # test CLI lookup res = testlib.blockstack_cli_lookup(fqn) if 'error' in res: print res return False print res if res['profile'] != {'type': 'Person', 'name': fqn}: print 'wrong profile' print res['profile'] return False # test REST lookup res = testlib.blockstack_REST_call("GET", "/v1/users/{}".format(fqn)) if 'error' in res: res['test'] = 'Failed to query name profile' print json.dumps(res) return False if res['http_status'] != 200 and res['http_status'] != 404: res['test'] = 'HTTP status {}, response = {} on name profile lookup'.format( res['http_status'], res['response']) print json.dumps(res) return False print res if res['response'] != {'type': 'Person', 'name': fqn}: print 'wrong profile on REST call' print res return False # test CLI lookup by address res = testlib.blockstack_cli_get_names_owned_by_address( wallets[i - 1].addr) if 'error' in res: print 'failed to get subdomains owned by {}'.format( wallets[i - 1].addr) print res return False if fqn not in res: print '{} not in list'.format(fqn) print res return False # test REST lookup by address res = testlib.blockstack_REST_call( 'GET', '/v1/addresses/bitcoin/{}'.format(wallets[i - 1].addr)) if 'error' in res: res['test'] = 'Failed to query names owned by address' print json.dumps(res) return False if res['http_status'] != 200 and res['http_status'] != 404: res['test'] = 'HTTP status {}, response = {} on address lookup'.format( res['http_status'], res['response']) print json.dumps(res) return False if fqn not in res['response']['names']: print '{} not in REST list'.format(fqn) print res return False # test REST get name history res = testlib.blockstack_REST_call('GET', '/v1/names/{}/history'.format(fqn)) if 'error' in res: res['test'] = 'Failed to query subdomain history' print json.dumps(res) return False if res['http_status'] != 200 and res['http_status'] != 404: res['test'] = 'HTTP status {}, response = {} on subdomain history lookup'.format( res['http_status'], res['response']) print json.dumps(res) return False blocks = res['response'] if len(blocks.keys()) != 2: print 'expected two updates' print blocks return False # get each historic zone file for block_height in blocks: for prev_state in blocks[block_height]: value_hash = prev_state['value_hash'] res = testlib.blockstack_REST_call( 'GET', '/v1/names/{}/zonefile/{}'.format(fqn, value_hash)) if 'error' in res: print 'failed to query zone file {} for {}'.format( value_hash, fqn) print json.dumps(res) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): start_transaction_broadcaster() start_subdomain_registrar() testlib.blockstack_namespace_preorder("id", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "id", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("id", wallets[1].privkey) testlib.next_block(**kw) wallet = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[2].privkey, wallets[3].privkey, wallets[4].privkey) resp = testlib.blockstack_name_preorder('foo.id', wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) zonefile = blockstack_client.zonefile.make_empty_zonefile('foo.id', None) zfdata = blockstack_zones.make_zone_file(zonefile) zfhash = blockstack.lib.storage.get_zonefile_data_hash(zfdata) resp = testlib.blockstack_name_register('foo.id', wallets[2].privkey, wallets[3].addr, zonefile_hash=zfhash) testlib.next_block(**kw) testlib.blockstack_put_zonefile(zfdata) # now, queue a subdomain registration. requests.post('http://localhost:3000/register', json={ 'zonefile': 'hello world', 'name': 'bar', 'owner_address': '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa' }) # force a batch out of the subdomain registrar requests.post('http://localhost:3000/issue_batch', headers={'Authorization': 'bearer tester129'}) for i in xrange(0, 12): testlib.next_block(**kw) print >> sys.stderr, "Waiting 10 seconds for the backend to pickup first batch" time.sleep(10) # update the name on-chain testlib.blockstack_name_update('foo.id', '11' * 20, wallets[3].privkey) testlib.blockstack_name_update('foo.id', '22' * 20, wallets[3].privkey) testlib.blockstack_name_update('foo.id', '33' * 20, wallets[3].privkey) testlib.next_block(**kw) # now, queue another registration requests.post('http://localhost:3000/register', json={ 'zonefile': 'hello world', 'name': 'zap', 'owner_address': '1Ez69SnzzmePmZX3WpEzMKTrcBF2gpNQ55' }) res = testlib.blockstack_REST_call('GET', '/v1/names/zap.foo.id', None) if 'error' in res: res['test'] = 'Failed to query zap.foo.id' print json.dumps(res) return False if res['http_status'] != 200: res['test'] = 'HTTP status {}, response = {} on name lookup'.format( res['http_status'], res['response']) print json.dumps(res) return False name_info = res['response'] try: if (name_info['zonefile'] != 'hello world' or name_info['address'] != '1Ez69SnzzmePmZX3WpEzMKTrcBF2gpNQ55'): res['test'] = 'Unexpected name info lookup for zap.foo.id' print 'zap.foo.id JSON:' print json.dumps(name_info) return False except: res['test'] = 'Unexpected name info lookup for zap.foo.id' print 'zap.foo.id JSON:' print json.dumps(name_info) return False # update the name on-chain again, but lots of times for i in range(0, 20): zonefile_pattern = '{:x}{:x}'.format(i / 16, i % 16) testlib.blockstack_name_update('foo.id', zonefile_pattern * 20, wallets[3].privkey) testlib.next_block(**kw) # should fail--we have too many prior zone files res = testlib.blockstack_REST_call('GET', '/v1/names/zap.foo.id', None) if res['http_status'] != 404: res['test'] = 'HTTP status {}, response = {} on name lookup'.format( res['http_status'], res['response']) print json.dumps(res) return False
def scenario( wallets, **kw ): zonefile_batches = [] testlib.blockstack_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey ) testlib.next_block( **kw ) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey ) testlib.next_block( **kw ) testlib.blockstack_namespace_ready( "test", wallets[1].privkey ) testlib.next_block( **kw ) testlib.blockstack_name_preorder( "foo1.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo2.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo3.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo4.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo5.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo6.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo7.test", wallets[2].privkey, wallets[3].addr ) testlib.next_block( **kw ) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' # send initial subdomain zone files zonefiles = { 'foo1.test': zf_template.format('foo1.test', subdomains.make_subdomain_txt('bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format('foo2.test', subdomains.make_subdomain_txt('bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format('foo3.test', subdomains.make_subdomain_txt('bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } zonefile_batches.append(zonefiles) testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.blockstack_name_register( "foo4.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register( "foo5.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register( "foo6.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.blockstack_name_register( "foo7.test", wallets[2].privkey, wallets[3].addr, zonefile_hash='11' * 20) testlib.next_block( **kw ) # send updates too, but via a different name each time for i in range(0, 3): zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format(i+1) name = 'foo{}.test'.format(i + 4) zonefiles = { 'foo1.test': zf_template.format(name, subdomains.make_subdomain_txt('bar.foo1.test', name, wallets[4].addr, i+1, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format(name, subdomains.make_subdomain_txt('bar.foo2.test', name, wallets[4].addr, i+1, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format(name, subdomains.make_subdomain_txt('bar.foo3.test', name, wallets[4].addr, i+1, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } zonefile_batches.append(zonefiles) testlib.blockstack_name_update(name, storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update(name, storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update(name, storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) # send all zonefiles at once for zfbatch in zonefile_batches: for name in zfbatch: assert testlib.blockstack_put_zonefile(zfbatch[name]) # kick off subdomain indexing testlib.next_block(**kw) # query each subdomain for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, hostport='http://localhost:16264') if 'error' in res: print res return False # should all have domain foo6.test at this time if res['domain'] != 'foo6.test': print 'wrong domain' print res return False expected_zonefile = zf_template.format(fqn, zf_default_url) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.next_block(**kw) # whois for i in xrange(1, 4): name = 'foo{}.test'.format(i) res = testlib.blockstack_cli_whois(name) if 'error' in res: print res return False if not res.has_key('zonefile_hash') or res[ 'zonefile_hash'] != storage.get_zonefile_data_hash( zonefiles[name]): print res return False if res['owner_address'] != wallets[3].addr: print res return False # upload zonefile assert testlib.blockstack_put_zonefile(zonefiles[name]) # kick off subdomain indexing testlib.next_block(**kw) # query each subdomain proxy = testlib.make_proxy() for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, proxy=proxy) if 'error' in res: print res return False expected_zonefile = zf_template.format(fqn, zf_default_url) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): global value_hashes testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) # register 10 names for i in xrange(0, 10): res = testlib.blockstack_name_preorder("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) for i in xrange(0, 10): res = testlib.blockstack_name_register("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) # make 10 empty zonefiles and propagate them for i in xrange(0, 10): data_pubkey = wallets[4].pubkey_hex empty_zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo_{}.test".format(i), data_pubkey, urls=["file:///tmp/foo_{}.test".format(i)]) empty_zonefile_str = blockstack_zones.make_zone_file(empty_zonefile) value_hash = blockstack_client.hash_zonefile(empty_zonefile) res = testlib.blockstack_name_update("foo_{}.test".format(i), value_hash, wallets[3].privkey) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) res = testlib.blockstack_put_zonefile(empty_zonefile_str) if not res: return False value_hashes.append(value_hash) testlib.next_block(**kw) print 'waiting for all zone files to replicate' time.sleep(10) config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG") assert config_path restore_dir = os.path.join(os.path.dirname(config_path), "snapshot_dir") # snapshot the latest backup snapshot_path = os.path.join(os.path.dirname(config_path), "snapshot.bsk") rc = blockstack.fast_sync_snapshot(kw['working_dir'], snapshot_path, wallets[3].privkey, None) if not rc: print "Failed to fast_sync_snapshot" return False if not os.path.exists(snapshot_path): print "Failed to create snapshot {}".format(snapshot_path) return False # sign with more keys for i in xrange(4, 6): rc = blockstack.fast_sync_sign_snapshot(snapshot_path, wallets[i].privkey) if not rc: print "Failed to sign with key {}".format(i) return False # restore! rc = restore( kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[4].pubkey_hex, wallets[5].pubkey_hex], 3) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore( kw['working_dir'], snapshot_path, restore_dir, [wallets[5].pubkey_hex, wallets[4].pubkey_hex, wallets[3].pubkey_hex], 3) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[4].pubkey_hex], 2) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[5].pubkey_hex], 2) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[4].pubkey_hex, wallets[5].pubkey_hex], 2) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex], 1) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[4].pubkey_hex, wallets[0].pubkey_hex], 1) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore( kw['working_dir'], snapshot_path, restore_dir, [wallets[0].pubkey_hex, wallets[1].pubkey_hex, wallets[5].pubkey_hex], 1) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False # should fail rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex], 2) if rc: print "restored insufficient signatures snapshot {}".format( snapshot_path) return False shutil.rmtree(restore_dir) # should fail rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[4].pubkey_hex], 3) if rc: print "restored insufficient signatures snapshot {}".format( snapshot_path) return False shutil.rmtree(restore_dir) # should fail rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[0].pubkey_hex], 1) if rc: print "restored wrongly-signed snapshot {}".format(snapshot_path) return False shutil.rmtree(restore_dir) # should fail rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[0].pubkey_hex, wallets[3].pubkey_hex], 2) if rc: print "restored wrongly-signed snapshot {}".format(snapshot_path) return False shutil.rmtree(restore_dir) # should fail rc = restore( kw['working_dir'], snapshot_path, restore_dir, [wallets[0].pubkey_hex, wallets[3].pubkey_hex, wallets[4].pubkey_hex], 3) if rc: print "restored wrongly-signed snapshot {}".format(snapshot_path) return False shutil.rmtree(restore_dir)
def scenario(wallets, **kw): global synchronized, value_hash import blockstack_integration_tests.atlas_network as atlas_network testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) # set up RPC daemon test_proxy = testlib.TestAPIProxy() blockstack_client.set_default_proxy(test_proxy) wallet_keys = blockstack_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[5].privkey) testlib.blockstack_client_set_wallet("0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey']) # register 10 names for i in xrange(0, 10): res = testlib.blockstack_name_preorder("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) for i in xrange(0, 10): res = testlib.blockstack_name_register("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) # start up an Atlas test network with 9 nodes: the main one doing the test, and 8 subordinate ones that treat it as a seed peer # organize nodes into a linear chain: node n is neighbor to n-1 and n+1, with the seed at one end. # nodes cannot talk to anyone else. atlas_nodes = [17000, 17001, 17002, 17003, 17004, 17005, 17006, 17007] atlas_topology = {} atlas_topology[17000] = [16264, 17001] atlas_topology[17007] = [17006] for i in xrange(1, len(atlas_nodes) - 1): atlas_topology[atlas_nodes[i]] = [ atlas_nodes[i - 1], atlas_nodes[i + 1] ] def chain_drop(src_hostport, dest_hostport): if src_hostport is None: return 0.0 src_host, src_port = blockstack_client.utils.url_to_host_port( src_hostport) dest_host, dest_port = blockstack_client.utils.url_to_host_port( dest_hostport) if (src_port == 16264 and dest_port == 17000) or (src_port == 17000 and dest_port == 16264): # seed end of the chain return 0.0 if abs(src_port - dest_port) <= 1: # chain link return 0.0 # drop otherwise return 1.0 network_des = atlas_network.atlas_network_build( testlib.working_dir(**kw), atlas_nodes, atlas_topology, {}, os.path.join(testlib.working_dir(**kw), "atlas_network")) atlas_network.atlas_network_start(network_des, drop_probability=chain_drop) print "Waiting 25 seconds for the altas peers to catch up" time.sleep(25.0) # make 10 empty zonefiles and propagate them for i in xrange(0, 10): data_pubkey = virtualchain.BitcoinPrivateKey( wallet_keys['data_privkey']).public_key().to_hex() empty_zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo_{}.test".format(i), data_pubkey, urls=["file:///tmp/foo_{}.test".format(i)]) empty_zonefile_str = blockstack_zones.make_zone_file(empty_zonefile) value_hash = blockstack_client.hash_zonefile(empty_zonefile) res = testlib.blockstack_name_update("foo_{}.test".format(i), value_hash, wallets[3].privkey) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) res = testlib.blockstack_put_zonefile(empty_zonefile_str) if not res: return False # wait at most 60 seconds for atlas network to converge synchronized = False for i in xrange(0, 60): atlas_network.atlas_print_network_state(network_des) if atlas_network.atlas_network_is_synchronized( network_des, testlib.last_block(**kw) - 1, 1): print "Synchronized!" sys.stdout.flush() synchronized = True break else: time.sleep(1.0) # shut down atlas_network.atlas_network_stop(network_des) if not synchronized: print "Not synchronized" sys.stdout.flush() return synchronized
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' zf_default_url_original = zf_default_url zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.next_block(**kw) # send these initial ones out assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) missing_zonefiles = [] # send updates too for i in range(0, 3): zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format( i + 1) zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, i + 1, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, i + 1, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, i + 1, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) if i % 2 == 0: # withhold for now missing_zonefiles.append(zonefiles) else: # send these out assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) assert len(missing_zonefiles) == 2 # verify that initial subdomains are present proxy = testlib.make_proxy() for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, proxy=proxy) if 'error' in res: print res return False if res['sequence'] != 0: print 'wrong sequence: expected 0' print res return False expected_zonefile = zf_template.format(fqn, zf_default_url_original) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # send first batch of withheld zonefiles assert testlib.blockstack_put_zonefile(missing_zonefiles[0]['foo1.test']) assert testlib.blockstack_put_zonefile(missing_zonefiles[0]['foo2.test']) assert testlib.blockstack_put_zonefile(missing_zonefiles[0]['foo3.test']) # kick off subdomain indexing testlib.next_block(**kw) # verify that we're now up to sequence=2 proxy = testlib.make_proxy() for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, proxy=proxy) if 'error' in res: print res return False if res['sequence'] != 2: print 'wrong sequence: expected 2' print res return False zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index=2"' expected_zonefile = zf_template.format(fqn, zf_default_url) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # send second batch of withheld zonefiles assert testlib.blockstack_put_zonefile(missing_zonefiles[1]['foo1.test']) assert testlib.blockstack_put_zonefile(missing_zonefiles[1]['foo2.test']) assert testlib.blockstack_put_zonefile(missing_zonefiles[1]['foo3.test']) # kick off subdomain indexing testlib.next_block(**kw) # query each subdomain (should all be at sequence 3) proxy = testlib.make_proxy() for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, proxy=proxy) if 'error' in res: print res return False if res['sequence'] != 3: print 'wrong sequence: expected 3' print res return False zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index=3"' expected_zonefile = zf_template.format(fqn, zf_default_url) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) # make zonefiles: # one normal one # one with a nonstandard zonefile zf1_txt = testlib.make_empty_zonefile('foo1.test', wallets[3].addr) zf2_txt = '\x00\x01\x02\x03\x04\x05' testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=blockstack.lib.storage.get_zonefile_data_hash(zf1_txt)) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=blockstack.lib.storage.get_zonefile_data_hash(zf2_txt)) testlib.next_block(**kw) # replicate zonefiles for zf in [zf1_txt, zf2_txt]: res = testlib.blockstack_put_zonefile(zf) assert res print 'waiting for zonefiles to be saved...' time.sleep(5) # store signed profile for each working_dir = kw['working_dir'] for name in ['foo1.test', 'foo2.test']: profile = {'name': name, 'type': '@Person', 'account': []} print 'sign profile for {}'.format(name) profile_path = os.path.join(working_dir, '{}.profile'.format(name)) with open(profile_path, 'w') as f: f.write(json.dumps(profile)) jwt = testlib.blockstack_cli_sign_profile(profile_path, wallets[3].privkey) if 'error' in jwt: print jwt return False jwt_path = os.path.join(working_dir, '{}.profile.jwt'.format(name)) with open(jwt_path, 'w') as f: f.write(json.dumps(jwt)) print 'verify profile for {}'.format(name) res = testlib.blockstack_cli_verify_profile(jwt_path, wallets[3].addr) if 'error' in res: print res return False print 'store profile for {}'.format(name) # store the jwt to the right place res = testlib.blockstack_put_profile(name, json.dumps(jwt), wallets[3].privkey, 'http://localhost:4000') assert res print 'lookup profile for {}'.format(name) # lookup res = testlib.blockstack_cli_lookup(name) if name != 'foo2.test': if 'error' in res: print res return False if res['profile'] != profile: print 'profile mismatch:' print res['profile'] print profile return False else: if 'zonefile' not in res or 'error' not in res['zonefile']: print res return False
def scenario(wallets, **kw): global value_hashes testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) # register 10 names for i in xrange(0, 10): res = testlib.blockstack_name_preorder("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) # make some subdomains zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' zonefiles = { 'foo_0.test': zf_template.format( 'foo_0.test', subdomains.make_subdomain_txt( 'bar.foo_0.test', 'foo_0.test', wallets[4].addr, 0, zf_template.format('bar.foo_0.test', zf_default_url), wallets[4].privkey)), 'foo_1.test': zf_template.format( 'foo_1.test', subdomains.make_subdomain_txt( 'bar.foo_1.test', 'foo_1.test', wallets[4].addr, 0, zf_template.format('bar.foo_1.test', zf_default_url), wallets[4].privkey)), 'foo_2.test': zf_template.format( 'foo_2.test', subdomains.make_subdomain_txt( 'bar.foo_2.test', 'foo_2.test', wallets[4].addr, 0, zf_template.format('bar.foo_2.test', zf_default_url), wallets[4].privkey)), 'foo_3.test': zf_template.format( 'foo_3.test', subdomains.make_subdomain_txt( 'bar.foo_3.test', 'foo_3.test', wallets[4].addr, 0, zf_template.format('bar.foo_3.test', zf_default_url), wallets[4].privkey)), 'foo_4.test': zf_template.format( 'foo_4.test', subdomains.make_subdomain_txt( 'bar.foo_4.test', 'foo_4.test', wallets[4].addr, 0, zf_template.format('bar.foo_4.test', zf_default_url), wallets[4].privkey)), 'foo_5.test': zf_template.format( 'foo_5.test', subdomains.make_subdomain_txt( 'bar.foo_5.test', 'foo_5.test', wallets[4].addr, 0, zf_template.format('bar.foo_5.test', zf_default_url), wallets[4].privkey)), 'foo_6.test': zf_template.format( 'foo_6.test', subdomains.make_subdomain_txt( 'bar.foo_6.test', 'foo_6.test', wallets[4].addr, 0, zf_template.format('bar.foo_6.test', zf_default_url), wallets[4].privkey)), 'foo_7.test': zf_template.format( 'foo_7.test', subdomains.make_subdomain_txt( 'bar.foo_7.test', 'foo_7.test', wallets[4].addr, 0, zf_template.format('bar.foo_7.test', zf_default_url), wallets[4].privkey)), 'foo_8.test': zf_template.format( 'foo_8.test', subdomains.make_subdomain_txt( 'bar.foo_8.test', 'foo_8.test', wallets[4].addr, 0, zf_template.format('bar.foo_8.test', zf_default_url), wallets[4].privkey)), 'foo_9.test': zf_template.format( 'foo_9.test', subdomains.make_subdomain_txt( 'bar.foo_9.test', 'foo_9.test', wallets[4].addr, 0, zf_template.format('bar.foo_9.test', zf_default_url), wallets[4].privkey)), } for i in xrange(0, 10): res = testlib.blockstack_name_register( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr, zonefile_hash=blockstack.lib.storage.get_zonefile_data_hash( zonefiles['foo_{}.test'.format(i)])) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) # propagate for name in zonefiles: assert testlib.blockstack_put_zonefile(zonefiles[name]) # process subdomains testlib.next_block(**kw) print 'waiting for all zone files to replicate' time.sleep(10) config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG") assert config_path restore_dir = os.path.join(os.path.dirname(config_path), "snapshot_dir") # snapshot the latest backup snapshot_path = os.path.join(os.path.dirname(config_path), "snapshot.bsk") rc = blockstack.fast_sync_snapshot(kw['working_dir'], snapshot_path, wallets[3].privkey, None) if not rc: print "Failed to fast_sync_snapshot" return False if not os.path.exists(snapshot_path): print "Failed to create snapshot {}".format(snapshot_path) return False # sign with more keys for i in xrange(4, 6): rc = blockstack.fast_sync_sign_snapshot(snapshot_path, wallets[i].privkey) if not rc: print "Failed to sign with key {}".format(i) return False # restore! rc = restore( kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[4].pubkey_hex, wallets[5].pubkey_hex], 3) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore( kw['working_dir'], snapshot_path, restore_dir, [wallets[5].pubkey_hex, wallets[4].pubkey_hex, wallets[3].pubkey_hex], 3) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[4].pubkey_hex], 2) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[5].pubkey_hex], 2) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[4].pubkey_hex, wallets[5].pubkey_hex], 2) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex], 1) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[4].pubkey_hex, wallets[0].pubkey_hex], 1) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False rc = restore( kw['working_dir'], snapshot_path, restore_dir, [wallets[0].pubkey_hex, wallets[1].pubkey_hex, wallets[5].pubkey_hex], 1) if not rc: print "failed to restore snapshot {}".format(snapshot_path) return False # should fail rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex], 2) if rc: print "restored insufficient signatures snapshot {}".format( snapshot_path) return False shutil.rmtree(restore_dir) # should fail rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[4].pubkey_hex], 3) if rc: print "restored insufficient signatures snapshot {}".format( snapshot_path) return False shutil.rmtree(restore_dir) # should fail rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[0].pubkey_hex], 1) if rc: print "restored wrongly-signed snapshot {}".format(snapshot_path) return False shutil.rmtree(restore_dir) # should fail rc = restore(kw['working_dir'], snapshot_path, restore_dir, [wallets[0].pubkey_hex, wallets[3].pubkey_hex], 2) if rc: print "restored wrongly-signed snapshot {}".format(snapshot_path) return False shutil.rmtree(restore_dir) # should fail rc = restore( kw['working_dir'], snapshot_path, restore_dir, [wallets[0].pubkey_hex, wallets[3].pubkey_hex, wallets[4].pubkey_hex], 3) if rc: print "restored wrongly-signed snapshot {}".format(snapshot_path) return False shutil.rmtree(restore_dir)
def scenario( wallets, **kw ): testlib.blockstack_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey ) testlib.next_block( **kw ) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey ) testlib.next_block( **kw ) testlib.blockstack_namespace_ready( "test", wallets[1].privkey ) testlib.next_block( **kw ) testlib.blockstack_name_preorder( "foo1.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo2.test", wallets[2].privkey, wallets[3].addr ) testlib.blockstack_name_preorder( "foo3.test", wallets[2].privkey, wallets[3].addr ) testlib.next_block( **kw ) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' # send initial zone files zonefiles = { 'foo1.test': zf_template.format('foo1.test', subdomains.make_subdomain_txt('bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format('foo2.test', subdomains.make_subdomain_txt('bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format('foo3.test', subdomains.make_subdomain_txt('bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.next_block( **kw ) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # subdomain history diagram # bar.foo1.test ++ #sequence ++ @zonefile_index # # # bar.foo1.test#2@3 (1) # / # bar.foo1.test#1@1 # / \ # / bar.foo1.test#2@4 (2) # bar.foo1.test#0 # \ bar.foo1.test#2@5 (3) # \ / # bar.foo1.test#1@2 # \ # bar.foo1.test#2@6 (4) # # # Send branches (1), (2), (3), and (4) # Reveal branches (4), then (3), then (2), then (1). Verify that the subdomain record matches the leaf node's state in order of revealing. def _send_batch(zf_default_url, seq): zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zonefiles = { 'foo1.test': zf_template.format('foo1.test', subdomains.make_subdomain_txt('bar.foo1.test', 'foo1.test', wallets[4].addr, seq, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format('foo2.test', subdomains.make_subdomain_txt('bar.foo2.test', 'foo2.test', wallets[4].addr, seq, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format('foo3.test', subdomains.make_subdomain_txt('bar.foo3.test', 'foo3.test', wallets[4].addr, seq, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_update('foo1.test', storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update('foo2.test', storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update('foo3.test', storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) return zonefiles def _query_subdomains(subdomain_names, expected_zonefiles, expected_sequence): # query each subdomain. Should get the latest for (fqn, expected_zonefile) in zip(subdomain_names, expected_zonefiles): res = client.get_name_record(fqn, hostport='http://localhost:16264') if 'error' in res: print res print 'failed to query {}'.format(fqn) return False if res['sequence'] != expected_sequence: print 'wrong sequence; expected {}'.format(expected_sequence) print res return False if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False return True branch_1 = [] branch_2 = [] branch_3 = [] branch_4 = [] # final branch URLs, since we're reorging only on sequence number branch_urls = [ '_https._tcp URI 10 1 "https://branch3-and-4.com"', '_https._tcp URI 10 1 "https://branch4.com"', '_https._tcp URI 10 1 "https://branch3.com"', '_https._tcp URI 10 1 "https://branch3.com"', '_https._tcp URI 10 1 "https://branch2.com"', '_https._tcp URI 10 1 "https://branch1.com"', ] # final sequence numbers, since we're reorging only on sequence number branch_sequences = [ 1, 2, 2, 2, 2, 2, ] # send branch 1 branch1_zfs = _send_batch('_https._tcp URI 10 1 "https://branch1-and-2.com"', 1) # branch_1.append(zfs) zfs = _send_batch('_https._tcp URI 10 1 "https://branch1.com"', 2) branch_1.append(zfs) # send branch 2 branch_2.append(branch1_zfs) zfs = _send_batch('_https._tcp URI 10 1 "https://branch2.com"', 2) branch_2.append(zfs) # send branch 3 branch3_zfs = _send_batch('_https._tcp URI 10 1 "https://branch3-and-4.com"', 1) # branch_3.append(zfs) zfs = _send_batch('_https._tcp URI 10 1 "https://branch3.com"', 2) branch_3.append(zfs) # send branch 4 branch_4.append(branch3_zfs) zfs = _send_batch('_https._tcp URI 10 1 "https://branch4.com"', 2) branch_4.append(zfs) # reveal in reverse. # branch_1 should be the final result b = 0 for j, branch in enumerate([branch_4, branch_3, branch_2, branch_1]): # reveal this branch, piecemeal for i, zf_batch in enumerate(branch): for name in zf_batch: print '' print 'reveal branch {}, node {}:\n{}'.format(4 - j, i+1, zf_batch[name]) print '' assert testlib.blockstack_put_zonefile(zf_batch[name]) testlib.next_block(**kw) # make sure all subdomains are consistent with this branch seq = branch_sequences[b] subdomain_names = ['bar.foo1.test', 'bar.foo2.test', 'bar.foo3.test'] zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = branch_urls[b] zonefiles = [ zf_template.format('bar.foo1.test', zf_default_url), zf_template.format('bar.foo2.test', zf_default_url), zf_template.format('bar.foo3.test', zf_default_url), ] print '' print 'check {} at sequence={} at branch {} node {}'.format(','.join(subdomain_names), seq, 4 - j, i+1) print '' rc = _query_subdomains(subdomain_names, zonefiles, seq) if not rc: print 'failed to query subdomains' return False b += 1 # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): global value_hashes, namespace_ids virtualchain_dir = kw['working_dir'] assert virtualchain_dir privkey = keylib.ECPrivateKey(wallets[4].privkey).to_hex() config_file = os.path.join(virtualchain_dir, 'snapshots.ini') privkey_path = os.path.join(virtualchain_dir, 'snapshots.pkey') snapshot_dir = os.path.join(virtualchain_dir, 'snapshots') with open(privkey_path, 'w') as f: f.write(privkey) with open(config_file, 'w') as f: f.write(""" [blockstack-snapshots] private_key = {} logfile = {} """.format(privkey_path, os.path.join(virtualchain_dir, 'snapshots.log'))) testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3) zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo.test", wallets[0].pubkey_hex) zonefile_txt = blockstack_zones.make_zone_file(zonefile) zonefile_hash = blockstack_client.storage.get_zonefile_data_hash( zonefile_txt) value_hashes.append(zonefile_hash) namespace_ids.append('test') resp = testlib.blockstack_name_import("imported.test", wallets[3].addr, zonefile_hash, wallets[1].privkey) if 'error' in resp: print json.dumps(resp, indent=4) return False testlib.next_block(**kw) # store zonefile res = testlib.blockstack_put_zonefile(zonefile_txt) assert res assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3) testlib.blockstack_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3) testlib.blockstack_name_register("foo.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3) zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo.test", wallets[0].pubkey_hex) zonefile_txt = blockstack_zones.make_zone_file(zonefile) zonefile_hash = blockstack_client.storage.get_zonefile_data_hash( zonefile_txt) value_hashes.append(zonefile_hash) testlib.blockstack_name_update('foo.test', zonefile_hash, wallets[3].privkey) testlib.next_block(**kw) time.sleep(1.0) # store zonefile res = testlib.blockstack_put_zonefile(zonefile_txt) assert res # there must be three snapshots res = os.listdir(snapshot_dir) assert len(res) == 4 assert 'snapshot.bsk' in res assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 1) # now there's only one res = os.listdir(snapshot_dir) assert len(res) == 2 assert 'snapshot.bsk' in res # restore it restore_dir = os.path.join(snapshot_dir, 'test_restore') res = restore(virtualchain_dir, os.path.join(snapshot_dir, 'snapshot.bsk'), restore_dir, [wallets[4].pubkey_hex], 1) assert res
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.next_block(**kw) # will send these later initial_zonefiles = zonefiles # send updates too for i in range(0, 3): zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format( i + 1) zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, i + 1, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, i + 1, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, i + 1, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # kick off subdomain indexing (nothing should happen) testlib.next_block(**kw) # store directly to Atlas zonefiles dir and wait a few seconds. Atlas should notice that they're here # and queue them for subdomain processing for name in ['foo1.test', 'foo2.test', 'foo3.test']: blockstack.lib.storage.store_atlas_zonefile_data( initial_zonefiles[name], blockstack.lib.get_blockstack_opts()['zonefiles']) print 'wait for atlas to discover that it already has the requisite zone files' time.sleep(10) # now kick it off again testlib.next_block(**kw) # query each subdomain for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, hostport='http://localhost:16264') if 'error' in res: print res return False expected_zonefile = zf_template.format(fqn, zf_default_url) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) preorder_block = str(testlib.get_current_block(**kw)) zfdata = 'hello world for the first time' zfhash = blockstack.lib.storage.get_zonefile_data_hash(zfdata) testlib.blockstack_name_register("foo.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=zfhash) testlib.next_block(**kw) register_block = str(testlib.get_current_block(**kw)) testlib.blockstack_put_zonefile(zfdata) name = 'foo.test' # get name and history--make sure it works name_rec = blockstack.lib.client.get_name_record( name, include_history=True, hostport='http://localhost:16264') if 'error' in name_rec: print name_rec return False if len(name_rec['history']) != 2: print 'invalid history' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False if preorder_block not in name_rec['history'] or len( name_rec['history'][preorder_block]) != 1: print 'missing preorder block' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False if register_block not in name_rec['history'] or len( name_rec['history'][register_block]) != 1: print 'missing register block' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False # do a bunch of updates in this block for i in xrange(0, 19): zfdata = 'hello update {}'.format(i) zfhash = blockstack.lib.storage.get_zonefile_data_hash(zfdata) testlib.blockstack_name_update("foo.test", zfhash, wallets[3].privkey) testlib.next_block(**kw) update_block_1 = str(testlib.get_current_block(**kw)) for i in xrange(0, 19): zfdata = 'hello update {}'.format(i) testlib.blockstack_put_zonefile(zfdata) # get name and history--make sure it works name_rec = blockstack.lib.client.get_name_record( name, include_history=True, hostport='http://localhost:16264') if 'error' in name_rec: print json.dumps(name_rec, indent=4, sort_keys=True) return False if len(name_rec['history']) != 3: print 'invalid history' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False # need to be 21 entries: the preorder, register, and 19 updates if preorder_block not in name_rec['history'] or len( name_rec['history'][preorder_block]) != 1: print 'missing preorder block' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False if register_block not in name_rec['history'] or len( name_rec['history'][register_block]) != 1: print 'missing register block' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False if update_block_1 not in name_rec['history'] or len( name_rec['history'][update_block_1]) != 19: print 'missing update block' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False # do a bunch more updates in this block for i in xrange(0, 21): zfdata = 'hello update round 2 {}'.format(i) zfhash = blockstack.lib.storage.get_zonefile_data_hash(zfdata) testlib.blockstack_name_update("foo.test", zfhash, wallets[3].privkey) testlib.next_block(**kw) update_block_2 = str(testlib.get_current_block(**kw)) for i in xrange(0, 21): zfdata = 'hello update round 2 {}'.format(i) testlib.blockstack_put_zonefile(zfdata) # get name and history--make sure it works name_rec = blockstack.lib.client.get_name_record( name, include_history=True, hostport='http://localhost:16264') if 'error' in name_rec: print json.dumps(name_rec, indent=4, sort_keys=True) return False if len(name_rec['history']) != 4: print 'invalid history' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False # need to be 21 entries: the preorder, register, and 19 updates if preorder_block not in name_rec['history'] or len( name_rec['history'][preorder_block]) != 1: print 'missing preorder block' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False if register_block not in name_rec['history'] or len( name_rec['history'][register_block]) != 1: print 'missing register block' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False if update_block_1 not in name_rec['history'] or len( name_rec['history'][update_block_1]) != 19: print 'missing update block 1' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False if update_block_2 not in name_rec['history'] or len( name_rec['history'][update_block_2]) != 21: print 'missing update block 2' print json.dumps(name_rec['history'], indent=4, sort_keys=True) return False # last page must be just the last updates hist_page = blockstack.lib.client.get_name_history_page( name, 0, hostport='http://localhost:16264') if 'error' in hist_page: print hist_page return False history = hist_page['history'] if len(history) != 1 or update_block_2 not in history: print 'missing update block 2 in history page' print json.dumps(history, indent=4, sort_keys=True) return False for vtx in history[update_block_2]: # should be vtxindex 2 through 21 if vtx['vtxindex'] < 2: print 'got low vtxindex' print json.dumps(history, indent=4, sort_keys=True) return False
def scenario(wallets, **kw): global synchronized, value_hash import blockstack_integration_tests.atlas_network as atlas_network testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) testlib.blockstack_name_register("foo.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) # set up RPC daemon test_proxy = testlib.TestAPIProxy() blockstack_client.set_default_proxy(test_proxy) wallet_keys = blockstack_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[5].privkey) testlib.blockstack_client_set_wallet("0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey']) # register 10 names for i in xrange(0, 10): res = testlib.blockstack_name_preorder("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) for i in xrange(0, 10): res = testlib.blockstack_name_register("foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) # make 10 empty zonefiles and propagate them for i in xrange(0, 10): data_pubkey = virtualchain.BitcoinPrivateKey( wallet_keys['data_privkey']).public_key().to_hex() empty_zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo_{}.test".format(i), data_pubkey, urls=["file:///tmp/foo_{}.test".format(i)]) empty_zonefile_str = blockstack_zones.make_zone_file(empty_zonefile) value_hash = blockstack_client.hash_zonefile(empty_zonefile) res = testlib.blockstack_name_update("foo_{}.test".format(i), value_hash, wallets[3].privkey) if 'error' in res: print json.dumps(res) return False testlib.next_block(**kw) res = testlib.blockstack_put_zonefile(empty_zonefile_str) if not res: return False # start up an atlas network with 16 peers, 8 of which will be active at once. # every second, have one peer come online, and one peer go offline. # have them all start out knowing about the same seed node. atlas_nodes = [ 17000, 17001, 17002, 17003, 17004, 17005, 17006, 17007, 17008, 17009, 17010, 17011, 17012, 17013, 17014, 17015, 17016 ] atlas_topology = {} for i in xrange(0, 9): atlas_topology[atlas_nodes[i]] = [16264] for i in xrange(9, len(atlas_nodes)): atlas_topology[atlas_nodes[i]] = [17008] atlas_topology[atlas_nodes[-1]].append(16264) # put the seed after the first four all_peers = atlas_nodes[:4] + [16264] + atlas_nodes[4:] time_start = int(time.time()) + 60 def churn_drop(src_hostport, dest_hostport): if src_hostport is None: return 0.0 src_host, src_port = blockstack_client.utils.url_to_host_port( src_hostport) dest_host, dest_port = blockstack_client.utils.url_to_host_port( dest_hostport) now = int(time.time()) # offset = (now - time_start) % len(all_peers) offset = now % len(all_peers) sample = all_peers + all_peers active_range = sample[offset:offset + 8] print "Active range: %s, request (%s --> %s)" % (active_range, src_port, dest_port) if src_port not in active_range: # dead return 1.0 if dest_port not in active_range: # dead return 1.0 return 0.0 network_des = atlas_network.atlas_network_build( testlib.working_dir(**kw), atlas_nodes, atlas_topology, {}, os.path.join(testlib.working_dir(**kw), "atlas_network")) atlas_network.atlas_network_start(network_des, drop_probability=churn_drop) print "Waiting 120 seconds for the altas peers to catch up" time.sleep(120.0) # wait at most 60 seconds for atlas network to converge synchronized = False for i in xrange(0, 60): atlas_network.atlas_print_network_state(network_des) if atlas_network.atlas_network_is_synchronized( network_des, testlib.last_block(**kw) - 1, 1): print "Synchronized!" synchronized = True break else: time.sleep(1.0) # shut down atlas_network.atlas_network_stop(network_des) return synchronized
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10, wallets[0].privkey) testlib.next_block(**kw) testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) testlib.blockstack_name_preorder("foo1.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey, wallets[3].addr) testlib.blockstack_name_preorder("foo3.test", wallets[2].privkey, wallets[3].addr) testlib.next_block(**kw) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://raw.githubusercontent.com/nobody/content/profile.md"' zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 0, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 0, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 0, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_register( "foo1.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo1.test'])) testlib.blockstack_name_register( "foo2.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo2.test'])) testlib.blockstack_name_register( "foo3.test", wallets[2].privkey, wallets[3].addr, zonefile_hash=storage.get_zonefile_data_hash(zonefiles['foo3.test'])) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # send two sequence=1 updates, but withhold the first batch. send the second batch now, and then send the first batch later to confirm # that each subdomain's history gets reorganized. # first sequence=1 update (withheld) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://test.com/withheld?index={}"'.format( 1) zf_default_url_reorg = zf_default_url zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 1, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 1, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 1, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } zonefiles_reorg = zonefiles testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) # second sequence=1 update (sent now) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format( 1) zf_default_url_seq1 = zf_default_url zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 1, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 1, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 1, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } zonefiles_seq1 = zonefiles testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) # sequence=2 (send now) zf_template = "$ORIGIN {}\n$TTL 3600\n{}" zf_default_url = '_https._tcp URI 10 1 "https://test.com/?index={}"'.format( 1) zonefiles = { 'foo1.test': zf_template.format( 'foo1.test', subdomains.make_subdomain_txt( 'bar.foo1.test', 'foo1.test', wallets[4].addr, 2, zf_template.format('bar.foo1.test', zf_default_url), wallets[4].privkey)), 'foo2.test': zf_template.format( 'foo2.test', subdomains.make_subdomain_txt( 'bar.foo2.test', 'foo2.test', wallets[4].addr, 2, zf_template.format('bar.foo2.test', zf_default_url), wallets[4].privkey)), 'foo3.test': zf_template.format( 'foo3.test', subdomains.make_subdomain_txt( 'bar.foo3.test', 'foo3.test', wallets[4].addr, 2, zf_template.format('bar.foo3.test', zf_default_url), wallets[4].privkey)), } testlib.blockstack_name_update( 'foo1.test', storage.get_zonefile_data_hash(zonefiles['foo1.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo2.test', storage.get_zonefile_data_hash(zonefiles['foo2.test']), wallets[3].privkey) testlib.blockstack_name_update( 'foo3.test', storage.get_zonefile_data_hash(zonefiles['foo3.test']), wallets[3].privkey) testlib.next_block(**kw) assert testlib.blockstack_put_zonefile(zonefiles['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles['foo3.test']) def _query_subdomains(): # query each subdomain. Should get the latest proxy = testlib.make_proxy() for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) res = client.get_name_record(fqn, proxy=proxy) if 'error' in res: print res return False expected_zonefile = zf_template.format(fqn, zf_default_url) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # should be in atlas as well zf = testlib.blockstack_get_zonefile(res['value_hash'], parse=False) if not zf: print 'no zone file {} in atlas'.format(res['value_hash']) return False if zf != expected_zonefile: print 'zonefile mismatch in atlas' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False return True # kick off subdomain indexing testlib.next_block(**kw) assert _query_subdomains() # query each subdomain history. sequence=1 should have test.com, but not 'withheld' for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) proxy = testlib.make_proxy() res = client.get_name_record(fqn, proxy=proxy, include_history=True) if 'error' in res: print res return False # expect zonefile expected_zonefile = zf_template.format(fqn, zf_default_url) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # find historic historic_blocks = res['history'].keys() historic_blocks.sort() historic_zfhash = res['history'][str( historic_blocks[1])][0]['value_hash'] # historic zone file (sequence=1) should NOT be withheld zf = testlib.blockstack_get_zonefile(historic_zfhash, parse=False) if not zf: print 'no zone file {} for sequence=1 in atlas'.format( res['value_hash']) return False expected_zonefile = zf_template.format(fqn, zf_default_url_seq1) if zf != expected_zonefile: print 'zonefile mismatch in atlas at sequence=1' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # reorg each zonefile's history assert testlib.blockstack_put_zonefile(zonefiles_reorg['foo1.test']) assert testlib.blockstack_put_zonefile(zonefiles_reorg['foo2.test']) assert testlib.blockstack_put_zonefile(zonefiles_reorg['foo3.test']) # kick off subdomain indexing testlib.next_block(**kw) assert _query_subdomains() # query each subdomain history. sequence=1 should have test.com, but with 'withheld' present in the URL for i in xrange(1, 4): fqn = 'bar.foo{}.test'.format(i) proxy = testlib.make_proxy() res = client.get_name_record(fqn, proxy=proxy, include_history=True) if 'error' in res: print res return False # expect zonefile expected_zonefile = zf_template.format(fqn, zf_default_url) if base64.b64decode(res['zonefile']) != expected_zonefile: print 'zonefile mismatch' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # find historic historic_blocks = res['history'].keys() historic_blocks.sort() historic_zfhash = res['history'][str( historic_blocks[1])][0]['value_hash'] # historic zone file (sequence=1) should NOT be withheld zf = testlib.blockstack_get_zonefile(historic_zfhash, parse=False) if not zf: print 'no zone file {} for sequence=1 in atlas'.format( res['value_hash']) return False expected_zonefile = zf_template.format(fqn, zf_default_url_reorg) if zf != expected_zonefile: print 'zonefile mismatch in atlas at sequence=1' print 'expected\n{}'.format(expected_zonefile) print 'got\n{}'.format(base64.b64decode(res['zonefile'])) return False # reindex assert testlib.check_subdomain_db(**kw)
def scenario( wallets, **kw ): global synchronized, value_hash import blockstack_integration_tests.atlas_network as atlas_network testlib.blockstack_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey ) testlib.next_block( **kw ) testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey ) testlib.next_block( **kw ) testlib.blockstack_namespace_ready( "test", wallets[1].privkey ) testlib.next_block( **kw ) testlib.blockstack_name_preorder( "foo.test", wallets[2].privkey, wallets[3].addr ) testlib.next_block( **kw ) testlib.blockstack_name_register( "foo.test", wallets[2].privkey, wallets[3].addr ) testlib.next_block( **kw ) # register 10 names for i in xrange(0, 10): res = testlib.blockstack_name_preorder( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr ) if 'error' in res: print json.dumps(res) return False testlib.next_block( **kw ) for i in xrange(0, 10): res = testlib.blockstack_name_register( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr ) if 'error' in res: print json.dumps(res) return False testlib.next_block( **kw ) # make 10 empty zonefiles and propagate them for i in xrange(0, 10): empty_zonefile_str = testlib.make_empty_zonefile( "foo_{}.test".format(i), wallets[3].addr) value_hash = blockstack.lib.storage.get_zonefile_data_hash(empty_zonefile_str) res = testlib.blockstack_name_update( "foo_{}.test".format(i), value_hash, wallets[3].privkey ) if 'error' in res: print json.dumps(res) return False testlib.next_block( **kw ) res = testlib.blockstack_put_zonefile(empty_zonefile_str) if not res: return False # start up an Atlas test network with 9 nodes: the main one doing the test, and 8 subordinate ones that treat it as a seed peer # only the seed node will be publicly routable; the other 8 will be unable to directly talk to each other. atlas_nodes = [17000, 17001, 17002, 17003, 17004, 17005, 17006, 17007] atlas_topology = {} for node_port in atlas_nodes: atlas_topology[node_port] = [16264] def nat_drop(src_hostport, dest_hostport): if dest_hostport is None: return 0.0 host, port = blockstack.lib.util.url_to_host_port( dest_hostport ) if port in atlas_nodes: # connections to the above nodes will always fail, since they're NAT'ed return 1.0 else: # connections to the seed node always succeed return 0.0 network_des = atlas_network.atlas_network_build( testlib.working_dir(**kw), atlas_nodes, atlas_topology, {}, os.path.join( testlib.working_dir(**kw), "atlas_network" ) ) atlas_network.atlas_network_start( network_des, drop_probability=nat_drop ) print "Waiting 60 seconds for the altas peers to catch up" time.sleep(60.0) # wait at most 60 seconds for atlas network to converge synchronized = False for i in xrange(0, 60): atlas_network.atlas_print_network_state( network_des ) if atlas_network.atlas_network_is_synchronized( network_des, testlib.last_block( **kw ) - 1, 1 ): print "Synchronized!" synchronized = True break else: time.sleep(1.0) # shut down atlas_network.atlas_network_stop( network_des ) return synchronized