Пример #1
0
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)
Пример #2
0
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
Пример #4
0
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
Пример #13
0
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
Пример #15
0
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)
Пример #16
0
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)
Пример #18
0
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
Пример #21
0
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
Пример #29
0
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)
Пример #30
0
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