Esempio n. 1
0
def scenario(wallets, **kw):

    global wallet_keys, error, foo_output, bar_output, baz_output, config_paths, put_benchmark_data, get_benchmark_data, aws_key, aws_secret

    print "patch '%s'" % os.environ.get("BLOCKSTACK_CLIENT_CONFIG")
    with open(os.environ.get('BLOCKSTACK_CLIENT_CONFIG'), "a+") as f:
        f.write(s3_config)
        f.flush()

    testlib.ysi_namespace_preorder("test", wallets[1].addr, wallets[0].privkey)
    testlib.next_block(**kw)

    testlib.ysi_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.ysi_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

    testlib.ysi_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.ysi_name_preorder("bar.test", wallets[5].privkey, wallets[6].addr)
    testlib.next_block(**kw)

    testlib.ysi_name_register("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.ysi_name_register("bar.test", wallets[5].privkey, wallets[6].addr)
    testlib.next_block(**kw)

    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy(test_proxy)
    wallet_keys['foo.test'] = ysi_client.make_wallet_keys(
        owner_privkey=wallets[3].privkey,
        data_privkey=wallets[4].privkey,
        payment_privkey=wallets[8].privkey)
    wallet_keys['bar.test'] = ysi_client.make_wallet_keys(
        owner_privkey=wallets[6].privkey,
        data_privkey=wallets[7].privkey,
        payment_privkey=wallets[9].privkey)

    # migrate profiles
    for name in ['foo.test', 'bar.test']:
        res = testlib.migrate_profile(name,
                                      proxy=test_proxy,
                                      wallet_keys=wallet_keys[name])
        if 'error' in res:
            res['test'] = 'Failed to initialize %s profile' % name
            print json.dumps(res, indent=4, sort_keys=True)
            error = True
            return

    testlib.next_block(**kw)

    # set up config file
    config_path = os.environ['BLOCKSTACK_FILE_CONFIG']
    with open(config_path, "w") as f:
        f.write(TEST_CONFIG_FILE)

    config_paths = {}

    # set up config file and upload file for each principal
    for name in ['foo.test', 'bar.test']:
        config_dir = os.path.dirname(config_path) + "." + name
        os.makedirs(config_dir)
        name_config_path = os.path.join(config_dir,
                                        os.path.basename(config_path))
        config_paths[name] = name_config_path

        # config path
        with open(config_paths[name], "w") as f:
            f.write(TEST_CONFIG_FILE)

        # upload paths
        for sz in file_sizes:
            upload_path = make_local_upload_path(config_path, name, sz)
            with open(upload_path, "w") as f:
                with open("/dev/urandom", "r") as r:
                    # generate file
                    file_data = r.read(sz)
                    f.write(file_data)
                    f.flush()

    foo_output = os.path.join(os.path.dirname(config_path), 'foo.test-out.txt')
    foo_fail_output = os.path.join(os.path.dirname(config_path),
                                   'foo.test-out-fail.txt')
    bar_output = os.path.join(os.path.dirname(config_path), 'bar.test-out.txt')
    bar_fail_output = os.path.join(os.path.dirname(config_path),
                                   'bar.test-out-fail.txt')

    # initialize file app
    res = ysi_file.file_key_regenerate("foo.test",
                                       "localhost",
                                       config_path=config_paths['foo.test'],
                                       wallet_keys=wallet_keys['foo.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    res = ysi_file.file_key_regenerate("bar.test",
                                       "localhost",
                                       config_path=config_paths['bar.test'],
                                       wallet_keys=wallet_keys['bar.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # send a file from foo.test to bar.test
    # do so many times
    for sz in file_sizes:
        put_benchmark_data[sz] = []
        for i in xrange(0, samples):
            upload_name = make_upload_name('foo.test', i, sz)
            local_path = make_local_upload_path(config_path, 'foo.test', sz)

            begin = time.time()
            res = ysi_file.file_put('foo.test',
                                    'localhost', ['bar.test'],
                                    upload_name,
                                    local_path,
                                    config_path=config_paths['foo.test'],
                                    wallet_keys=wallet_keys['foo.test'])

            end = time.time()

            if 'error' in res:
                print json.dumps(res, indent=4, sort_keys=True)
                error = True
                return

            put_benchmark_data[sz].append(end - begin)

    # get a file from foo.test, as bar.test
    # do so many times
    for sz in file_sizes:
        get_benchmark_data[sz] = []
        for i in xrange(0, samples):
            upload_name = make_upload_name('foo.test', i, sz)
            src_local_path = make_local_upload_path(config_path, 'foo.test',
                                                    sz)
            local_path = make_local_upload_path(config_path, 'bar.test', sz)

            begin = time.time()
            res = ysi_file.file_get('bar.test',
                                    'localhost',
                                    'foo.test',
                                    upload_name,
                                    local_path,
                                    config_path=config_paths['bar.test'],
                                    wallet_keys=wallet_keys['bar.test'])
            end = time.time()
            if 'error' in res:
                print json.dumps(res, indent=4, sort_keys=True)
                error = True
                return

            rc = os.system("cmp \"%s\" \"%s\"" % (src_local_path, local_path))
            if rc != 0:
                raise Exception("Not equal: \"%s\" and \"%s\"" %
                                (src_local_path, local_path))
            try:
                os.unlink(output_path)
            except:
                pass

            get_benchmark_data[sz].append(end - begin)

    # delete
    for sz in file_sizes:
        for i in xrange(0, samples):
            upload_name = make_upload_name('foo.test', i, sz)
            res = ysi_file.file_delete('foo.test',
                                       upload_name,
                                       config_path=config_paths['foo.test'],
                                       wallet_keys=wallet_keys['foo.test'])
            if 'error' in res:
                print json.dumps(res, indent=4, sort_keys=True)
                error = True
                return
def scenario(wallets, **kw):

    global synchronized, value_hash

    import ysi_integration_tests.atlas_network as atlas_network

    testlib.ysi_namespace_preorder("test", wallets[1].addr, wallets[0].privkey)
    testlib.next_block(**kw)

    testlib.ysi_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.ysi_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

    # set up RPC daemon
    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy(test_proxy)
    wallet_keys = ysi_client.make_wallet_keys(
        owner_privkey=wallets[3].privkey,
        data_privkey=wallets[4].privkey,
        payment_privkey=wallets[5].privkey)
    testlib.ysi_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.ysi_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.ysi_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 = ysi_client.utils.url_to_host_port(src_hostport)
        dest_host, dest_port = ysi_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(
        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 = ysi_client.zonefile.make_empty_zonefile(
            "foo_{}.test".format(i),
            data_pubkey,
            urls=["file:///tmp/foo_{}.test".format(i)])
        empty_zonefile_str = ysi_zones.make_zone_file(empty_zonefile)
        value_hash = ysi_client.hash_zonefile(empty_zonefile)

        res = testlib.ysi_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)

        # propagate
        res = testlib.ysi_cli_sync_zonefile('foo_{}.test'.format(i),
                                            zonefile_string=empty_zonefile_str)
        if 'error' in res:
            print json.dumps(res)
            return False

    # wait at most 60 seconds for atlas network to converge
    synchronized = False
    for i in xrange(0, 60):
        atlas_network.atlas_print_network_state(network_des)
        if atlas_network.atlas_network_is_synchronized(
                network_des,
                testlib.last_block(**kw) - 1, 1):
            print "Synchronized!"
            sys.stdout.flush()
            synchronized = True
            break

        else:
            time.sleep(1.0)

    # shut down
    atlas_network.atlas_network_stop(network_des)
    if not synchronized:
        print "Not synchronized"
        sys.stdout.flush()

    return synchronized
def scenario( wallets, **kw ):

    global synchronized

    import ysi_integration_tests.atlas_network as atlas_network

    testlib.ysi_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.ysi_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.ysi_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    # set up RPC daemon
    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy( test_proxy )
    wallet_keys = ysi_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[5].privkey )
    testlib.ysi_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.ysi_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.ysi_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 a simple Atlas test network with two nodes: the main one doing the test, and a subordinate one that treats it as a seed peer.
    network_des = atlas_network.atlas_network_build( [17000], {17000: [16264]}, {}, os.path.join( testlib.working_dir(**kw), "atlas_network" ))
    atlas_network.atlas_network_start( network_des )

    time.sleep(5.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 = ysi_client.zonefile.make_empty_zonefile( "foo_{}.test".format(i), data_pubkey, urls=["file:///tmp/foo_{}.test".format(i)] )
        empty_zonefile_str = ysi_zones.make_zone_file( empty_zonefile )
        value_hash = ysi_client.hash_zonefile( empty_zonefile )

        res = testlib.ysi_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 )

        # propagate 
        res = testlib.ysi_cli_sync_zonefile('foo_{}.test'.format(i), zonefile_string=empty_zonefile_str)
        if 'error' in res:
            print json.dumps(res)
            return False

    # wait at most 10 seconds for atlas network to converge
    synchronized = False
    for i in xrange(0, 10):
        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
Esempio n. 4
0
def scenario(wallets, **kw):

    global wallet_keys, wallet_keys_2, key_names, error

    testlib.ysi_namespace_preorder("test", wallets[1].addr, wallets[0].privkey)
    testlib.next_block(**kw)

    testlib.ysi_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.ysi_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

    testlib.ysi_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.next_block(**kw)

    testlib.ysi_name_register("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.next_block(**kw)

    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy(test_proxy)
    wallet_keys = ysi_client.make_wallet_keys(
        owner_privkey=wallets[3].privkey,
        data_privkey=wallets[4].privkey,
        payment_privkey=wallets[5].privkey)

    # migrate profiles
    res = testlib.migrate_profile("foo.test",
                                  proxy=test_proxy,
                                  wallet_keys=wallet_keys)
    if 'error' in res:
        res['test'] = 'Failed to initialize foo.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # tell serialization-checker that value_hash can be ignored in this block
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    testlib.next_block(**kw)

    # make an account
    res = testlib.ysi_cli_put_account("foo.test",
                                      "serviceFoo",
                                      "serviceFooID",
                                      "foo://bar.com",
                                      None,
                                      extra_data='foofield=foo!',
                                      wallet_keys=wallet_keys)
    if 'error' in res:
        res['test'] = 'Failed to create foo.test account'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    res = testlib.ysi_cli_put_account("foo.test",
                                      "deletedService",
                                      "deletedServiceID",
                                      "foo://deleted",
                                      None,
                                      extra_data='barfield=bar!',
                                      wallet_keys=wallet_keys)
    if 'error' in res:
        res['test'] = 'Failed to create foo.test deletedService account'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # delete an account
    res = testlib.ysi_cli_delete_account("foo.test",
                                         "deletedService",
                                         "deletedServiceID",
                                         None,
                                         wallet_keys=wallet_keys)
    if 'error' in res:
        res['test'] = 'Failed to delete foo.test deletedService'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    testlib.next_block(**kw)
Esempio n. 5
0
def scenario( wallets, **kw ):

    global wallet_keys, error, index_file_data, resource_data

    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy( test_proxy )
    wallet_keys = ysi_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[5].privkey )
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] )

    testlib.ysi_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.ysi_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.ysi_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    testlib.ysi_name_preorder( "foo.test", wallets[2].privkey, wallets[3].addr )
    testlib.next_block( **kw )
    
    testlib.ysi_name_register( "foo.test", wallets[2].privkey, wallets[3].addr )
    testlib.next_block( **kw )
    
    # migrate profiles 
    res = testlib.migrate_profile( "foo.test", proxy=test_proxy, wallet_keys=wallet_keys )
    if 'error' in res:
        res['test'] = 'Failed to initialize foo.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 
    
    res = testlib.start_api("0123456789abcdef")
    if 'error' in res:
        print 'failed to start API: {}'.format(res)
        return False

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    testlib.next_block( **kw )
   
    # sign in and make a token 
    datastore_pk = keylib.ECPrivateKey(wallets[-1].privkey).to_hex()
    res = testlib.ysi_cli_app_signin("foo.test", datastore_pk, 'http://localhost:8888', ['store_read', 'store_write', 'store_admin'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 
    
    ses = res['token']

    # export to environment 
    ysi_client.set_secret("BLOCKSTACK_API_SESSION", ses)

    datastore_id_res = testlib.ysi_cli_datastore_get_id( datastore_pk )
    datastore_id = datastore_id_res['datastore_id']

    # use random data for file 
    file_data = None
    with open('/dev/urandom', 'r') as f:
        file_data = f.read(16384)

    # make datastore 
    res = testlib.ysi_cli_create_datastore( "foo.test", datastore_pk, ['disk'], ses )
    if 'error' in res:
        print "failed to create datastore: {}".format(res['error'])
        return False

    # make directories
    for dpath in ['/dir1', '/dir2', '/dir1/dir3', '/dir1/dir3/dir4']:
        print 'mkdir {}'.format(dpath)
        res = testlib.ysi_cli_datastore_mkdir( "foo.test", datastore_pk, dpath, ses )
        if 'error' in res:
            print 'failed to mkdir {}: {}'.format(dpath, res['error'])
            return False

    # make directories again (should fail with EEXIST)
    for dpath in ['/dir1', '/dir2', '/dir1/dir3', '/dir1/dir3/dir4']:
        print 'mkdir {} (should fail)'.format(dpath)
        res = testlib.ysi_cli_datastore_mkdir( "foo.test", datastore_pk, dpath, ses )
        if 'error' not in res:
            print 'accidentally succeeded to mkdir {}: {}'.format(dpath, res)
            return False

        if not res.has_key('errno'):
            print 'no errno in error {}'.format(res)
            return False

        if res['errno'] != errno.EEXIST:
            print 'wrong errno in error {}'.format(res)
            return False

    # stat directories 
    for dpath in ['/dir1', '/dir2', '/dir1/dir3', '/dir1/dir3/dir4']:
        print 'stat {}'.format(dpath)
        res = testlib.ysi_cli_datastore_stat( "foo.test", datastore_id, dpath, ses )
        if 'error' in res:
            print 'failed to stat {}: {}'.format(dpath, res['error'])
            return False

        if res['type'] != ysi_client.schemas.MUTABLE_DATUM_DIR_TYPE:
            print 'not a directory: {}, {}'.format(dpath, res)
            return False

    # list directories 
    for dpath, expected in [('/', ['dir1', 'dir2']), ('/dir1', ['dir3']), ('/dir1/dir3', ['dir4']), ('/dir1/dir3/dir4', [])]:
        print 'listdir {}'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir( "foo.test", datastore_id, dpath, ses )
        if 'error' in res:
            print 'failed to listdir {}: {}'.format(dpath, res['error'])
            return False

        print res
        if len(res['children'].keys()) != len(expected):
            print 'invalid directory: expected:\n{}\ngot:\n{}\n'.format(expected, res)
            return False

        for child in expected: 
            if not res['children'].has_key(child):
                print 'invalid directory: missing {} in {}'.format(child, res)
                return False

    # put files 
    for dpath in ['/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4', '/dir1/dir3/dir4/file5']:
        print 'putfile {}'.format(dpath)
        data = '{} hello {}'.format(file_data, dpath)
        res = testlib.ysi_cli_datastore_putfile( "foo.test", datastore_pk, dpath, data, ses )
        if 'error' in res:
            print 'failed to putfile {}: {}'.format(dpath, res['error'])
            return False

    # stat files
    for dpath in ['/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4', '/dir1/dir3/dir4/file5']:
        print 'stat {}'.format(dpath)
        res = testlib.ysi_cli_datastore_stat( "foo.test", datastore_id, dpath, ses )
        if 'error' in res:
            print 'failed to stat {}: {}'.format(dpath, res['error'])
            return False

        if res['type'] != ysi_client.schemas.MUTABLE_DATUM_FILE_TYPE:
            print 'not a file: {}, {}'.format(dpath, res)
            return False

    # list directories again 
    for dpath, expected in [('/', ['dir1', 'dir2', 'file1', 'file2']), ('/dir1', ['dir3', 'file3']), ('/dir1/dir3', ['dir4', 'file4']), ('/dir1/dir3/dir4', ['file5'])]:
        print 'listdir {}'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir( "foo.test", datastore_id, dpath, ses )
        if 'error' in res:
            print 'failed to listdir {}: {}'.format(dpath, res['error'])
            return False

        if len(res['children'].keys()) != len(expected):
            print 'invalid directory: expected:\n{}\ngot:\n{}\n'.format(expected, res)
            return False

        for child in expected: 
            if not res['children'].has_key(child):
                print 'invalid directory: missing {} in {}'.format(child, res)
                return False
     
    # get files
    for dpath in ['/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4', '/dir1/dir3/dir4/file5']:
        print 'getfile {}'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile( "foo.test", datastore_id, dpath, ses )
        if 'error' in res:
            print 'failed to getfile {}: {}'.format(dpath, res['error'])
            return False

        if res != '{} hello {}'.format(file_data, dpath):
            print 'failed to read {}'.format(dpath)
            return False

    # put files again! 
    for dpath in ['/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4', '/dir1/dir3/dir4/file5']:
        print 'putfile {}'.format(dpath)
        data = '{} hello 2 {}'.format(file_data, dpath)
        res = testlib.ysi_cli_datastore_putfile( "foo.test", datastore_pk, dpath, data, ses )
        if 'error' in res:
            print 'failed to putfile {}: {}'.format(dpath, res['error'])
            return False

    # get files again!
    for dpath in ['/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4', '/dir1/dir3/dir4/file5']:
        print 'getfile {}'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile( "foo.test", datastore_id, dpath, ses )
        if 'error' in res:
            print 'failed to getfile {}: {}'.format(dpath, res['error'])
            return False

        if res != '{} hello 2 {}'.format(file_data, dpath):
            print 'failed to read {}'.format(dpath)
            return False

    # remove files
    for dpath in ['/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4', '/dir1/dir3/dir4/file5']:
        print 'deletefile {}'.format(dpath)
        res = testlib.ysi_cli_datastore_deletefile( "foo.test", datastore_pk, dpath, ses )
        if 'error' in res:
            print 'failed to deletefile {}: {}'.format(dpath, res['error'])
            return False

    # stat files (should all fail)
    for dpath in ['/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4', '/dir1/dir3/dir4/file5']:
        print 'stat {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_stat( "foo.test", datastore_id, dpath, ses )
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to stat {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False
 
    # get files (should all fail)
    for dpath in ['/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4', '/dir1/dir3/dir4/file5']:
        print 'getfile {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile( "foo.test", datastore_id, dpath, ses )
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to get {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False

    # list directories, 3rd time 
    for dpath, expected in [('/', ['dir1', 'dir2']), ('/dir1', ['dir3']), ('/dir1/dir3', ['dir4']), ('/dir1/dir3/dir4', [])]:
        print 'listdir {}'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir( "foo.test", datastore_id, dpath, ses )
        if 'error' in res:
            print 'failed to listdir {}: {}'.format(dpath, res['error'])
            return False

        if len(res['children'].keys()) != len(expected):
            print 'invalid directory: expected:\n{}\ngot:\n{}\n'.format(expected, res)
            return False

        for child in expected: 
            if not res['children'].has_key(child):
                print 'invalid directory: missing {} in {}'.format(child, res)
                return False

    # remove directories 
    for dpath in ['/dir1/dir3/dir4', '/dir1/dir3', '/dir2', '/dir1']:
        print 'rmdir {}'.format(dpath)
        res = testlib.ysi_cli_datastore_rmdir( "foo.test", datastore_pk, dpath, ses )
        if 'error' in res:
            print 'failed to rmdir {}: {}'.format(dpath, res['error'])
            return False

    # stat directories (should all fail)
    for dpath in ['/dir1/dir3/dir4', '/dir1/dir3', '/dir2', '/dir1']:
        print 'stat {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_stat( "foo.test", datastore_id, dpath, ses )
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to stat {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False

    # list directories (should all fail) 
    for dpath, expected in [('/dir1', ['dir3']), ('/dir1/dir3', ['dir4']), ('/dir1/dir3/dir4', [])]:
        print 'listdir {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir( "foo.test", datastore_id, dpath, ses )
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to list {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False

    # remove directories again (should fail) 
    for dpath in ['/dir1/dir3/dir4', '/dir1/dir3', '/dir2', '/dir1']:
        print 'rmdir {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_rmdir( "foo.test", datastore_pk, dpath, ses )
        if 'error' not in res:
            print 'accidentally succeeded to rmdir twice: {}'.format(res)
            return False

        if res.get('errno') != errno.ENOENT:
            print 'wrong errno on rmdir: {}'.format(res)
            return False

    # root should be empty 
    print 'listdir {}'.format('/')
    res = testlib.ysi_cli_datastore_listdir( "foo.test", datastore_id, '/', ses )
    if 'error' in res:
        print 'failed to listdir /: {}'.format(res['error'])
        return False

    if len(res['children'].keys()) > 0:
        print 'root still has children: {}'.format(res['children'].keys())
        return False

    # delete datastore 
    print 'delete datastore'
    res = testlib.ysi_cli_delete_datastore( "foo.test", datastore_pk, ses )
    if 'error' in res:
        print 'failed to delete foo-app.com datastore'
        print json.dumps(res)
        return False

    # no more data in disk driver 
    names = os.listdir("/tmp/ysi-disk/mutable")
    if names != ['foo.test']:
        print 'improper cleanup'
        return False

    testlib.next_block( **kw )
Esempio n. 6
0
def scenario(wallets, **kw):

    global wallet_keys, error, index_file_data, resource_data

    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy(test_proxy)
    wallet_keys = ysi_client.make_wallet_keys(
        owner_privkey=wallets[3].privkey,
        data_privkey=wallets[4].privkey,
        payment_privkey=wallets[5].privkey)
    testlib.ysi_client_set_wallet("0123456789abcdef",
                                  wallet_keys['payment_privkey'],
                                  wallet_keys['owner_privkey'],
                                  wallet_keys['data_privkey'])

    testlib.ysi_namespace_preorder("test", wallets[1].addr, wallets[0].privkey)
    testlib.next_block(**kw)

    testlib.ysi_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.ysi_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

    testlib.ysi_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.next_block(**kw)

    testlib.ysi_name_register("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.next_block(**kw)

    # migrate profiles
    res = testlib.migrate_profile("foo.test",
                                  proxy=test_proxy,
                                  wallet_keys=wallet_keys)
    if 'error' in res:
        res['test'] = 'Failed to initialize foo.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    testlib.next_block(**kw)

    res = testlib.start_api("0123456789abcdef")
    if 'error' in res:
        print 'failed to start API: {}'.format(res)
        return False

    # sign in and make a token
    datastore_pk = keylib.ECPrivateKey(wallets[-1].privkey).to_hex()
    res = testlib.ysi_cli_app_signin(
        "foo.test", datastore_pk, 'http://localhost:8888',
        ['store_read', 'store_write', 'store_admin'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # export to environment
    ysi_client.set_secret("BLOCKSTACK_API_SESSION", res['token'])
    ses = res['token']

    datastore_id_res = testlib.ysi_cli_datastore_get_id(datastore_pk)
    datastore_id = datastore_id_res['datastore_id']

    # use random data for file
    file_data = None
    with open('/dev/urandom', 'r') as f:
        file_data = f.read(16384)

    # make datastore with two storage drivers
    res = testlib.ysi_cli_create_datastore('foo.test', datastore_pk,
                                           ['disk', 'test'], ses)
    if 'error' in res:
        print "failed to create datastore: {}".format(res['error'])
        return False

    # simulate a failure in the 'test' driver
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '1')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    # make directories (should all fail, since 'test' is offline; however, 'disk' will have worked)
    for dpath in ['/dir1', '/dir2', '/dir1/dir3', '/dir1/dir3/dir4']:
        print 'mkdir {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_mkdir('foo.test', datastore_pk, dpath,
                                              ses)
        if 'error' not in res:
            print 'accidentally succeeded to mkdir {}: {}'.format(dpath, res)
            return False

    # stat directories (should all fail locally due to ENOENT, since the parent directory will not have been updated)
    for dpath in ['/dir1/dir3/dir4', '/dir1/dir3', '/dir2', '/dir1']:
        print 'stat {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_stat('foo.test', datastore_id, dpath,
                                             ses)
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to stat {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False

    # list directories (all the ones we tried to create should fail due to ENOENT)
    for dpath, expected in [('/dir1', ['dir3']), ('/dir1/dir3', ['dir4']),
                            ('/dir1/dir3/dir4', [])]:
        print 'listdir {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to list {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False

    # restore driver
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '0')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    # make directories (should succeed)
    for dpath in ['/dir1', '/dir2', '/dir1/dir3', '/dir1/dir3/dir4']:
        print 'mkdir {}'.format(dpath)
        res = testlib.ysi_cli_datastore_mkdir('foo.test', datastore_pk, dpath,
                                              ses)
        if 'error' in res:
            print 'failed to mkdir {}: {}'.format(dpath, res['error'])
            return False

    # make directories (should fail with EEXIST)
    for dpath in ['/dir1', '/dir2', '/dir1/dir3', '/dir1/dir3/dir4']:
        print 'mkdir {}'.format(dpath)
        res = testlib.ysi_cli_datastore_mkdir('foo.test', datastore_pk, dpath,
                                              ses)
        if 'error' not in res:
            print 'accidentally succeeded to mkdir {}: {}'.format(dpath, res)
            return False

        if not res.has_key('errno'):
            print 'no errno in error {}'.format(res)
            return False

        if res['errno'] != errno.EEXIST:
            print 'wrong errno in error {}'.format(res)
            return False

    # stat directories (should succeed)
    for dpath in ['/dir1', '/dir2', '/dir1/dir3', '/dir1/dir3/dir4']:
        print 'stat {}'.format(dpath)
        res = testlib.ysi_cli_datastore_stat('foo.test', datastore_id, dpath,
                                             ses)
        if 'error' in res:
            print 'failed to stat {}: {}'.format(dpath, res['error'])
            return False

        if res['type'] != ysi_client.schemas.MUTABLE_DATUM_DIR_TYPE:
            print 'not a directory: {}, {}'.format(dpath, res)
            return False

    # list directories (should succeed)
    for dpath, expected in [('/', ['dir1', 'dir2']), ('/dir1', ['dir3']),
                            ('/dir1/dir3', ['dir4']), ('/dir1/dir3/dir4', [])]:
        print 'listdir {}'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' in res:
            print 'failed to listdir {}: {}'.format(dpath, res['error'])
            return False

        if len(res['children'].keys()) != len(expected):
            print 'invalid directory: expected:\n{}\ngot:\n{}\n'.format(
                expected, res)
            return False

        for child in expected:
            if not res['children'].has_key(child):
                print 'invalid directory: missing {} in {}'.format(child, res)
                return False

    # put files
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'putfile {}'.format(dpath)
        data = '{} hello {}'.format(file_data, dpath)
        res = testlib.ysi_cli_datastore_putfile('foo.test', datastore_pk,
                                                dpath, data, ses)
        if 'error' in res:
            print 'failed to putfile {}: {}'.format(dpath, res['error'])
            return False

    # simulate a failure in the 'test' driver
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '1')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    # stat files (should succeed)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'stat {} (should still work)'.format(dpath)
        res = testlib.ysi_cli_datastore_stat('foo.test', datastore_id, dpath,
                                             ses)
        if 'error' in res:
            print 'failed to stat {}: {}'.format(dpath, res['error'])
            return False

        if res['type'] != ysi_client.schemas.MUTABLE_DATUM_FILE_TYPE:
            print 'not a file: {}, {}'.format(dpath, res)
            return False

    # list directories again (should succeed)
    for dpath, expected in [('/', ['dir1', 'dir2', 'file1', 'file2']),
                            ('/dir1', ['dir3', 'file3']),
                            ('/dir1/dir3', ['dir4', 'file4']),
                            ('/dir1/dir3/dir4', ['file5'])]:
        print 'listdir {} (should still work)'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' in res:
            print 'failed to listdir {}: {}'.format(dpath, res['error'])
            return False

        if len(res['children'].keys()) != len(expected):
            print 'invalid directory: expected:\n{}\ngot:\n{}\n'.format(
                expected, res)
            return False

        for child in expected:
            if not res['children'].has_key(child):
                print 'invalid directory: missing {} in {}'.format(child, res)
                return False

    # get files (should succeed and return latest data)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'getfile {} (should still work)'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' in res:
            print 'failed to getfile {}: {}'.format(dpath, res['error'])
            return False

        if res != '{} hello {}'.format(file_data, dpath):
            print 'failed to read {}'.format(dpath)
            return False

    # put files (should succeed with 'disk', but fail overall since we have a failed driver)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'putfile {} (expect failure)'.format(dpath)
        data = '{} hello 2 {}'.format(file_data, dpath)
        res = testlib.ysi_cli_datastore_putfile('foo.test', datastore_pk,
                                                dpath, data, ses)
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to putfile {}: {}'.format(
                dpath, res['error'])
            return False

    # get files (should get the new data, despite the failed service)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'getfile {} (should still work)'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' in res:
            print 'failed to getfile {}: {}'.format(dpath, res['error'])
            return False

        if res != '{} hello 2 {}'.format(file_data, dpath):
            print 'failed to read {}'.format(dpath)
            return False

    # restore test driver
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '0')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    # put files (should succeed now)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'putfile {}'.format(dpath)
        data = '{} hello 2 {}'.format(file_data, dpath)
        res = testlib.ysi_cli_datastore_putfile('foo.test', datastore_pk,
                                                dpath, data, ses)
        if 'error' in res:
            print 'failed to putfile {}: {}'.format(dpath, res['error'])
            return False

    # get files again! should see results of last put
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'getfile {}'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' in res:
            print 'failed to getfile {}: {}'.format(dpath, res['error'])
            return False

        if res != '{} hello 2 {}'.format(file_data, dpath):
            print 'failed to read {}'.format(dpath)
            return False

    # simulate a failure in the 'test' driver
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '1')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    # remove files (should fail since 'test' driver is disabled)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'deletefile {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_deletefile('foo.test', datastore_pk,
                                                   dpath, ses)
        if 'error' not in res:
            print 'accidentally failed to deletefile {}: {}'.format(
                dpath, res['error'])
            return False

    # get files (should fail, since the idata was removed from 'disk')
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'getfile {} (should fail)'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' not in res:
            print 'accidentally got {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.EREMOTEIO:
            print 'wrong errno: {}'.format(res)
            return False

    # stat files (should still work)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'stat {} (should still work)'.format(dpath)
        res = testlib.ysi_cli_datastore_stat('foo.test', datastore_id, dpath,
                                             ses)
        if 'error' in res:
            print 'failed to stat {}: {}'.format(path, res)
            return False

    # restore test driver
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '0')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    # stat files (should still work)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'stat {}'.format(dpath)
        res = testlib.ysi_cli_datastore_stat('foo.test', datastore_id, dpath,
                                             ses)
        if 'error' in res:
            print 'failed to stat {}: {}'.format(path, res)
            return False

    # remove files (should work now)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'deletefile {}'.format(dpath)
        res = testlib.ysi_cli_datastore_deletefile('foo.test', datastore_pk,
                                                   dpath, ses)
        if 'error' in res:
            print 'failed to deletefile {}: {}'.format(dpath, res)
            return False

    # put file data (should succeed on both 'disk' and 'test')
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'putfile {}'.format(dpath)
        data = '{} hello 3 {}'.format(file_data, dpath)
        res = testlib.ysi_cli_datastore_putfile('foo.test', datastore_pk,
                                                dpath, data, ses)
        if 'error' in res:
            print 'failed to putfile {}: {}'.format(dpath, res['error'])
            return False

    # get files again! should see results of last put
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'getfile {}'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' in res:
            print 'failed to getfile {}: {}'.format(dpath, res['error'])
            return False

        if res != '{} hello 3 {}'.format(file_data, dpath):
            print 'failed to read {}'.format(dpath)
            return False

    # cause 'test' to fail
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '1')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    # put file data (should fail, but succeed on 'disk')
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'putfile {} (expect failure)'.format(dpath)
        data = '{} hello 4 {}'.format(file_data, dpath)
        res = testlib.ysi_cli_datastore_putfile('foo.test', datastore_pk,
                                                dpath, data, ses)
        if 'error' not in res:
            print 'accidentally succeeded to putfile {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.EREMOTEIO:
            print 'wrong errno: {}'.format(res)
            return False

    # get files again! should see results of last put
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'getfile {}'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' in res:
            print 'failed to getfile {}: {}'.format(dpath, res['error'])
            return False

        if res != '{} hello 4 {}'.format(file_data, dpath):
            print 'failed to read {}'.format(dpath)
            return False

    # restore 'test'
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '0')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    # get files again! should see results of last put
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'getfile {}'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' in res:
            print 'failed to getfile {}: {}'.format(dpath, res['error'])
            return False

        if res != '{} hello 4 {}'.format(file_data, dpath):
            print 'failed to read {}'.format(dpath)
            return False

    # remove files (should succeed)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'deletefile {}'.format(dpath)
        res = testlib.ysi_cli_datastore_deletefile('foo.test', datastore_pk,
                                                   dpath, ses)
        if 'error' in res:
            print 'failed to deletefile {}: {}'.format(dpath, res['error'])
            return False

    # stat files (should all fail)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'stat {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_stat('foo.test', datastore_id, dpath,
                                             ses)
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to stat {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False

    # get files (should all fail)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'getfile {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to get {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False

    # list directories
    for dpath, expected in [('/', ['dir1', 'dir2']), ('/dir1', ['dir3']),
                            ('/dir2', []), ('/dir1/dir3', ['dir4']),
                            ('/dir1/dir3/dir4', [])]:
        print 'listdir {}'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' in res:
            print 'failed to listdir {}: {}'.format(dpath, res['error'])
            return False

        if len(res['children'].keys()) != len(expected):
            print 'invalid directory: expected:\n{}\ngot:\n{}\n'.format(
                expected, res)
            return False

        for child in expected:
            if not res['children'].has_key(child):
                print 'invalid directory: missing {} in {}'.format(child, res)
                return False

    # break 'test'
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '1')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    # stat files (should all fail)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'stat {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_stat('foo.test', datastore_id, dpath,
                                             ses)
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to stat {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False

    # get files (should all fail)
    for dpath in [
            '/file1', '/file2', '/dir1/file3', '/dir1/dir3/file4',
            '/dir1/dir3/dir4/file5'
    ]:
        print 'getfile {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_getfile('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to get {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False

    # list directories
    for dpath, expected in [('/', ['dir1', 'dir2']), ('/dir1', ['dir3']),
                            ('/dir2', []), ('/dir1/dir3', ['dir4']),
                            ('/dir1/dir3/dir4', [])]:
        print 'listdir {}'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' in res:
            print 'failed to listdir {}: {}'.format(dpath, res['error'])
            return False

        if len(res['children'].keys()) != len(expected):
            print 'invalid directory: expected:\n{}\ngot:\n{}\n'.format(
                expected, res)
            return False

        for child in expected:
            if not res['children'].has_key(child):
                print 'invalid directory: missing {} in {}'.format(child, res)
                return False

    # remove directories (should fail, but '/dir2' and '/dir1/dir3/dir4''s idata should be gone)
    for dpath in ['/dir1/dir3/dir4', '/dir1/dir3', '/dir2', '/dir1']:
        print 'rmdir {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_rmdir('foo.test', datastore_pk, dpath,
                                              ses)
        if 'error' not in res:
            print 'accidentally succeeded to rmdir {}: {}'.format(dpath, res)
            return False

        if dpath not in ['/dir1/dir3/dir4', '/dir2']:
            if res.get('errno') != errno.ENOTEMPTY:
                print 'wrong errno for deleting {}'.format(res)
                return False

    # list directories (should fail for /dir1/dir3/dir4 and /dir2 since its idata got deleted, but it should still work for everyone else)
    for dpath, expected in [('/dir2', []), ('/dir1/dir3/dir4', [])]:
        print 'listdir {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to list {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.EREMOTEIO:
            print 'wrong errno: {}'.format(res)
            return False

    # these should still work
    for dpath, expected in [('/', ['dir1', 'dir2']), ('/dir1', ['dir3']),
                            ('/dir1/dir3', ['dir4'])]:
        print 'listdir {} (should still work)'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' in res:
            print 'failed to listdir {}: {}'.format(dpath, res['error'])
            return False

        if len(res['children'].keys()) != len(expected):
            print 'invalid directory: expected:\n{}\ngot:\n{}\n'.format(
                expected, res)
            return False

        for child in expected:
            if not res['children'].has_key(child):
                print 'invalid directory: missing {} in {}'.format(child, res)
                return False

    # restore service
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '0')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    # remove directories (should succeed)
    for dpath in ['/dir1/dir3/dir4', '/dir1/dir3', '/dir2', '/dir1']:
        print 'rmdir {}'.format(dpath)
        res = testlib.ysi_cli_datastore_rmdir('foo.test', datastore_pk, dpath,
                                              ses)
        if 'error' in res:
            print 'failed to rmdir {}: {}'.format(dpath, res['error'])
            return False

    # stat directories (should all fail)
    for dpath in ['/dir1/dir3/dir4', '/dir1/dir3', '/dir2', '/dir1']:
        print 'stat {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_stat('foo.test', datastore_id, dpath,
                                             ses)
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to stat {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False

    # list directories (should all fail)
    for dpath, expected in [('/dir2', []), ('/dir1', ['dir3']),
                            ('/dir1/dir3', ['dir4']), ('/dir1/dir3/dir4', [])]:
        print 'listdir {} (expect failure)'.format(dpath)
        res = testlib.ysi_cli_datastore_listdir('foo.test', datastore_id,
                                                dpath, ses)
        if 'error' not in res or 'errno' not in res:
            print 'accidentally succeeded to list {}: {}'.format(dpath, res)
            return False

        if res['errno'] != errno.ENOENT:
            print 'wrong errno: {}'.format(res)
            return False

    # root should be empty
    print 'listdir {}'.format('/')
    res = testlib.ysi_cli_datastore_listdir('foo.test', datastore_id, '/', ses)
    if 'error' in res:
        print 'failed to listdir /: {}'.format(res['error'])
        return False

    if len(res['children'].keys()) > 0:
        print 'root still has children: {}'.format(res['children'].keys())
        return False

    # simulate a failure in the 'test' driver
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '1')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    # delete datastore (should fail)
    print 'delete datastore (expect failure)'
    res = testlib.ysi_cli_delete_datastore('foo.test', datastore_pk, ses)
    if 'error' not in res:
        print 'accidentally succeeded to delete datastore'
        print json.dumps(res)
        return False

    # restore service
    res = testlib.ysi_test_setenv(
        'BLOCKSTACK_INTEGRATION_TEST_STORAGE_FAILURE', '0')
    if 'error' in res:
        print 'failed to setenv: {}'.format(res)
        return False

    print 'delete datastore'
    res = testlib.ysi_cli_delete_datastore('foo.test', datastore_pk, ses)
    if 'error' in res:
        print 'failed to delete foo-app.com datastore'
        print json.dumps(res)
        return False

    # no more data in test-disk driver
    names = os.listdir("/tmp/ysi-integration-test-storage/mutable")
    if names != ['foo.test']:
        print 'improper cleanup on test'
        return False

    # due to our failed mkdir of /dir1 and /dir2, these
    # will have leaked. Expect 5 entries (including foo.test):
    # an idata and inode header for both dirs
    names = os.listdir("/tmp/ysi-disk/mutable")
    if len(names) != 5:
        print 'imporper cleanup on disk'
        return False

    if 'foo.test' not in names:
        print 'missing foo.test'
        return False

    testlib.next_block(**kw)
def scenario(wallets, **kw):

    global wallet_keys, error, foo_output, bar_output, baz_output, config_paths

    testlib.ysi_namespace_preorder("test", wallets[1].addr, wallets[0].privkey)
    testlib.next_block(**kw)

    testlib.ysi_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.ysi_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

    testlib.ysi_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.ysi_name_preorder("bar.test", wallets[5].privkey, wallets[6].addr)
    testlib.ysi_name_preorder("baz.test", wallets[8].privkey, wallets[9].addr)
    testlib.next_block(**kw)

    testlib.ysi_name_register("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.ysi_name_register("bar.test", wallets[5].privkey, wallets[6].addr)
    testlib.ysi_name_register("baz.test", wallets[8].privkey, wallets[9].addr)
    testlib.next_block(**kw)

    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy(test_proxy)
    wallet_keys['foo.test'] = ysi_client.make_wallet_keys(
        owner_privkey=wallets[3].privkey, payment_privkey=wallets[10].privkey)
    wallet_keys['bar.test'] = ysi_client.make_wallet_keys(
        owner_privkey=wallets[6].privkey, payment_privkey=wallets[11].privkey)
    wallet_keys['baz.test'] = ysi_client.make_wallet_keys(
        owner_privkey=wallets[9].privkey, payment_privkey=wallets[12].privkey)

    # migrate profiles
    for name in ['foo.test', 'bar.test', 'baz.test']:
        res = testlib.migrate_profile(name,
                                      proxy=test_proxy,
                                      wallet_keys=wallet_keys[name])
        if 'error' in res:
            res['test'] = 'Failed to initialize %s profile' % name
            print json.dumps(res, indent=4, sort_keys=True)
            error = True
            return

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    testlib.next_block(**kw)

    # set up config file
    config_path = os.environ['BLOCKSTACK_FILE_CONFIG']
    with open(config_path, "w") as f:
        f.write(TEST_CONFIG_FILE)

    config_paths = {}

    # set up config file and directory for each principal
    for name in ['foo.test', 'bar.test', 'baz.test']:
        config_dir = os.path.dirname(config_path) + "." + name
        os.makedirs(config_dir)
        name_config_path = os.path.join(config_dir,
                                        os.path.basename(config_path))
        config_paths[name] = name_config_path

        with open(config_paths[name], "w") as f:
            f.write(TEST_CONFIG_FILE)

    foo_output = os.path.join(os.path.dirname(config_path), 'foo.test-out.txt')
    foo_fail_output = os.path.join(os.path.dirname(config_path),
                                   'foo.test-out-fail.txt')
    bar_output = os.path.join(os.path.dirname(config_path), 'bar.test-out.txt')
    bar_fail_output = os.path.join(os.path.dirname(config_path),
                                   'bar.test-out-fail.txt')
    baz_output = os.path.join(os.path.dirname(config_path), 'baz.test-out.txt')
    baz_fail_output = os.path.join(os.path.dirname(config_path),
                                   'baz.test-out-fail.txt')

    # initialize file app
    res = ysi_file.file_key_regenerate("foo.test",
                                       "localhost",
                                       config_path=config_paths['foo.test'],
                                       wallet_keys=wallet_keys['foo.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    res = ysi_file.file_key_regenerate("bar.test",
                                       "localhost",
                                       config_path=config_paths['bar.test'],
                                       wallet_keys=wallet_keys['bar.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    res = ysi_file.file_key_regenerate("bar.test",
                                       "mobile-phone",
                                       config_path=config_paths['bar.test'],
                                       wallet_keys=wallet_keys['bar.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    res = ysi_file.file_key_regenerate("baz.test",
                                       "laptop",
                                       config_path=config_paths['baz.test'],
                                       wallet_keys=wallet_keys['baz.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # send a file from foo.test to bar.test and baz.test
    res = ysi_file.file_put('foo.test',
                            'localhost', ['bar.test', 'baz.test'],
                            'config-file-from-foo.test',
                            config_path,
                            config_path=config_paths['foo.test'],
                            wallet_keys=wallet_keys['foo.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # send a file from bar.test's mobile phone to foo.test (but not baz.test)
    res = ysi_file.file_put('bar.test',
                            'mobile-phone', ['foo.test'],
                            'config-file-from-bar.test',
                            config_path,
                            config_path=config_paths['bar.test'],
                            wallet_keys=wallet_keys['bar.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # send a file from baz.test's laptop to baz.test's laptop (and no one else)
    res = ysi_file.file_put('baz.test',
                            'laptop', [],
                            'config-file-from-baz.test',
                            config_path,
                            config_path=config_paths['baz.test'],
                            wallet_keys=wallet_keys['baz.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # have foo.test receive bar.test's file
    log.debug("foo.test receives bar.test's file")
    res = ysi_file.file_get('foo.test',
                            'localhost',
                            'bar.test',
                            'config-file-from-bar.test',
                            foo_output,
                            config_path=config_paths['foo.test'],
                            wallet_keys=wallet_keys['foo.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # have bar.test receive bar.test's file to localhost
    log.debug("bar.test receives bar.tests's file")
    res = ysi_file.file_get('bar.test',
                            'localhost',
                            'bar.test',
                            'config-file-from-bar.test',
                            bar_output,
                            config_path=config_paths['bar.test'],
                            wallet_keys=wallet_keys['bar.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # have baz.test receive foo.test's file
    log.debug("baz.test recieves foo.test's file")
    res = ysi_file.file_get('baz.test',
                            'laptop',
                            'foo.test',
                            'config-file-from-foo.test',
                            baz_output,
                            config_path=config_paths['baz.test'],
                            wallet_keys=wallet_keys['baz.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # have bar.test receive foo.test's file to its mobile-phone key
    log.debug("bar.test receives foo.test's file")
    res = ysi_file.file_get('bar.test',
                            'mobile-phone',
                            'foo.test',
                            'config-file-from-foo.test',
                            bar_output,
                            config_path=config_paths['bar.test'],
                            wallet_keys=wallet_keys['bar.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # have baz.test try to receive bar.test's file (should fail)
    log.debug("baz.test receives bar.test's file (should fail)")
    res = ysi_file.file_get('baz.test',
                            'laptop',
                            'bar.test',
                            'config-file-from-bar.test',
                            baz_fail_output,
                            config_path=config_paths['baz.test'],
                            wallet_keys=wallet_keys['baz.test'])
    print json.dumps(res, indent=4, sort_keys=True)
    if 'error' not in res or res['error'] != 'Failed to decrypt data':
        print 'baz decrypting hidden file: succeeded when we should not have, or failed incorrectly: %s' % res
        error = True
        return

    # have foo.test and bar.test try to receive baz.test's file (should fail)
    for (name, failpath) in [('foo.test', foo_fail_output),
                             ('bar.test', bar_fail_output)]:
        log.debug("%s receives baz.test's file (should fail)" % name)
        res = ysi_file.file_get(name,
                                'localhost',
                                'baz.test',
                                'config-file-from-baz.test',
                                failpath,
                                config_path=config_paths[name],
                                wallet_keys=wallet_keys[name])
        print json.dumps(res, indent=4, sort_keys=True)
        if 'error' not in res or res['error'] != 'Failed to decrypt data':
            print '%s decrypting hidden file: succeeded when we should not have, or fialed incorrectly: %s' % (
                name, res)
            error = True
            return

    # regenerate everyone's keys
    res = ysi_file.file_key_regenerate("foo.test",
                                       "localhost",
                                       config_path=config_paths['foo.test'],
                                       wallet_keys=wallet_keys['foo.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    res = ysi_file.file_key_regenerate("bar.test",
                                       "localhost",
                                       config_path=config_paths['bar.test'],
                                       wallet_keys=wallet_keys['bar.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    res = ysi_file.file_key_regenerate("bar.test",
                                       "mobile-phone",
                                       config_path=config_paths['bar.test'],
                                       wallet_keys=wallet_keys['bar.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    res = ysi_file.file_key_regenerate("baz.test",
                                       "laptop",
                                       config_path=config_paths['baz.test'],
                                       wallet_keys=wallet_keys['baz.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # have foo.test receive bar.test's file, despite regeneration
    log.debug("foo.test receives bar.test's file, despite regeneration")
    res = ysi_file.file_get('foo.test',
                            'localhost',
                            'bar.test',
                            'config-file-from-bar.test',
                            foo_output,
                            config_path=config_paths['foo.test'],
                            wallet_keys=wallet_keys['foo.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    if 'warning' not in res or res['warning'] != 'Used stale key':
        print json.dumps(res, indent=4, sort_keys=True)
        print "did not use stale key"
        error = True
        return

    # have bar.test receive bar.test's file to localhost
    log.debug("bar.test receives bar.tests's file, despite regeneration")
    res = ysi_file.file_get('bar.test',
                            'localhost',
                            'bar.test',
                            'config-file-from-bar.test',
                            bar_output,
                            config_path=config_paths['bar.test'],
                            wallet_keys=wallet_keys['bar.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    if 'warning' not in res or res['warning'] != 'Used stale key':
        print json.dumps(res, indent=4, sort_keys=True)
        print "did not use stale key"
        error = True
        return

    # have baz.test receive foo.test's file
    log.debug("baz.test recieves foo.test's file, despite regeneration")
    res = ysi_file.file_get('baz.test',
                            'laptop',
                            'foo.test',
                            'config-file-from-foo.test',
                            baz_output,
                            config_path=config_paths['baz.test'],
                            wallet_keys=wallet_keys['baz.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    if 'warning' not in res or res['warning'] != 'Used stale key':
        print json.dumps(res, indent=4, sort_keys=True)
        print "did not use stale key"
        error = True
        return

    # have bar.test receive foo.test's file to its mobile-phone key
    log.debug("bar.test receives foo.test's file, despite regeneration")
    res = ysi_file.file_get('bar.test',
                            'mobile-phone',
                            'foo.test',
                            'config-file-from-foo.test',
                            bar_output,
                            config_path=config_paths['bar.test'],
                            wallet_keys=wallet_keys['bar.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    if 'warning' not in res or res['warning'] != 'Used stale key':
        print json.dumps(res, indent=4, sort_keys=True)
        print "did not use stale key"
        error = True
        return

    # delete the file from foo
    log.debug("delete foo.test's file")
    res = ysi_file.file_delete('foo.test',
                               'config-file-from-foo.test',
                               config_path=config_paths['foo.test'],
                               wallet_keys=wallet_keys['foo.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # delete the file from bar
    log.debug("delete bar.test's file")
    res = ysi_file.file_delete('bar.test',
                               'config-file-from-bar.test',
                               config_path=config_paths['bar.test'],
                               wallet_keys=wallet_keys['bar.test'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # verify that no one can read foo's file
    for (name, host, failpath) in [('foo.test', 'localhost', foo_fail_output),
                                   ('bar.test', 'mobile-phone',
                                    bar_fail_output),
                                   ('baz.test', 'laptop', baz_fail_output)]:
        log.debug("%s receives foo.test's deleted file (should fail)" % name)
        res = ysi_file.file_get(name,
                                host,
                                'foo.test',
                                'config-file-from-foo.test',
                                failpath,
                                config_path=config_paths[name],
                                wallet_keys=wallet_keys[name])
        print json.dumps(res, indent=4, sort_keys=True)
        if 'error' not in res or res['error'] != 'Failed to get encrypted file':
            print 'reading deleted file: succeeded when we should not have, or failed incorrectly: %s' % res
            error = True
            return
def scenario( wallets, **kw ):

    global synchronized, value_hash

    import ysi_integration_tests.atlas_network as atlas_network

    testlib.ysi_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.ysi_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.ysi_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    testlib.ysi_name_preorder( "foo.test", wallets[2].privkey, wallets[3].addr )
    testlib.next_block( **kw )
    
    testlib.ysi_name_register( "foo.test", wallets[2].privkey, wallets[3].addr )
    testlib.next_block( **kw )

    # set up RPC daemon
    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy( test_proxy )
    wallet_keys = ysi_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[5].privkey )
    testlib.ysi_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.ysi_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.ysi_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 = ysi_client.zonefile.make_empty_zonefile( "foo_{}.test".format(i), data_pubkey, urls=["file:///tmp/foo_{}.test".format(i)] )
        empty_zonefile_str = ysi_zones.make_zone_file( empty_zonefile )
        value_hash = ysi_client.hash_zonefile( empty_zonefile )

        res = testlib.ysi_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 )

        # propagate 
        res = testlib.ysi_cli_sync_zonefile('foo_{}.test'.format(i), zonefile_string=empty_zonefile_str)
        if 'error' in res:
            print json.dumps(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 = ysi_client.utils.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( 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
Esempio n. 9
0
def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, key_names, error, gpghome


    testlib.ysi_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.ysi_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.ysi_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    testlib.ysi_name_preorder( "foo.test", wallets[2].privkey, wallets[3].addr )
    testlib.ysi_name_preorder( "bar.test", wallets[5].privkey, wallets[6].addr )
    testlib.next_block( **kw )
    
    testlib.ysi_name_register( "foo.test", wallets[2].privkey, wallets[3].addr )
    testlib.ysi_name_register( "bar.test", wallets[5].privkey, wallets[6].addr )
    testlib.next_block( **kw )

    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy( test_proxy )
    wallet_keys = ysi_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[8].privkey )
    wallet_keys_2 = ysi_client.make_wallet_keys( owner_privkey=wallets[6].privkey, data_privkey=wallets[7].privkey, payment_privkey=wallets[9].privkey )

    # migrate profiles 
    res = testlib.migrate_profile( "foo.test", proxy=test_proxy, wallet_keys=wallet_keys )
    if 'error' in res:
        res['test'] = 'Failed to initialize foo.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

    res = testlib.migrate_profile( "bar.test", proxy=test_proxy, wallet_keys=wallet_keys_2 )
    if 'error' in res:
        res['test'] = 'Failed to initialize bar.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    testlib.next_block( **kw )

    # add account keys 
    res = ysi_gpg.gpg_profile_create_key( "foo.test", "foo_test_account_key", immutable=False,
                                                proxy=test_proxy, wallet_keys=wallet_keys, config_dir=testlib.get_working_dir(**kw),
                                                gpghome=testlib.gpg_key_dir(**kw), use_key_server=False )

    if 'error' in res:
        res['test'] = 'Failed to create foo.test account key'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

    else:
        key_names['foo.test'].append( res )

    res = ysi_gpg.gpg_profile_create_key( "bar.test", "bar_test_account_key", immutable=False,
                                                proxy=test_proxy, wallet_keys=wallet_keys_2, config_dir=testlib.get_working_dir(**kw),
                                                gpghome=testlib.gpg_key_dir(**kw), use_key_server=False )

    if 'error' in res:
        res['test'] = 'Failed to create bar.test account key'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

    else:
        key_names['bar.test'].append( res )

    testlib.next_block( **kw )

    # add immutable app keys
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] ) 
    res = ysi_gpg.gpg_app_create_key( "foo.test", "secure_messaging", "foo_test_immutable_secmsg_key", immutable=True,
                                              proxy=test_proxy, wallet_keys=wallet_keys, config_dir=testlib.get_working_dir(**kw) )

    if 'error' in res:
        res['test'] = 'Failed to create foo.test immutable app key'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 
    else:
        key_names['foo.test'].append( res )

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    # wait for it to go through
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    print "wait for confirmation"
    time.sleep(10)
    
    # set new wallet keys
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys_2['payment_privkey'], wallet_keys_2['owner_privkey'], wallet_keys_2['data_privkey'] ) 
    res = ysi_gpg.gpg_app_create_key( "bar.test", "secure_messaging", "bar_test_immutable_secmsg_key", immutable=True,
                                                proxy=test_proxy, wallet_keys=wallet_keys_2, config_dir=testlib.get_working_dir(**kw) )

    if 'error' in res:
        res['test'] = 'Failed to create bar.test immutable app key'
        print json.dumps(res, indent=4, sort_keys=True )
        error = True
        return
    else:
        key_names['bar.test'].append( res )

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    # wait for it to go through
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    print "wait for confirmation"
    time.sleep(10)

    # add mutable app keys 
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] ) 
    res = ysi_gpg.gpg_app_create_key( "foo.test", "less-secure_messaging", "foo_test_mutable_secmsg_key",
                                                proxy=test_proxy, wallet_keys=wallet_keys, config_dir=testlib.get_working_dir(**kw) )

    if 'error' in res:
        res['test'] = 'Failed to create foo.test mutable app key'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return
    else:
        key_names['foo.test'].append( res )

    testlib.next_block( **kw )
    
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys_2['payment_privkey'], wallet_keys_2['owner_privkey'], wallet_keys_2['data_privkey'] ) 
    res = ysi_gpg.gpg_app_create_key( "bar.test", "less-secure_messaging", "bar_test_mutable_secmsg_key",
                                                proxy=test_proxy, wallet_keys=wallet_keys_2, config_dir=testlib.get_working_dir(**kw) )

    if 'error' in res:
        res['test'] = 'Failed to create bar.test mutable app key'
        print json.dumps(res, indent=4, sort_keys=True )
        error = True
        return
    else:
        key_names['bar.test'].append( res )

    testlib.next_block( **kw )

    # add profile keys that we'll delete
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] ) 
    res = ysi_gpg.gpg_profile_create_key( "foo.test", "foo_test_deleted_account_key", immutable=True,
                                                proxy=test_proxy, wallet_keys=wallet_keys, config_dir=testlib.get_working_dir(**kw),
                                                gpghome=testlib.gpg_key_dir(**kw), use_key_server=False)

    foo_profile_delete_key_id = None
    if 'error' in res:
        res['test'] = 'Failed to create deletable foo.test account key'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return
    else:
        key_names['foo.test'].append( res )
        foo_profile_delete_key_id = res['key_id']

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    # wait for it to go through
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    print "wait for confirmation"
    time.sleep(10)

    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys_2['payment_privkey'], wallet_keys_2['owner_privkey'], wallet_keys_2['data_privkey'] ) 
    res = ysi_gpg.gpg_profile_create_key( "bar.test", "bar_test_deleted_account_key", immutable=True,
                                                proxy=test_proxy, wallet_keys=wallet_keys_2, config_dir=testlib.get_working_dir(**kw),
                                                gpghome=testlib.gpg_key_dir(**kw), use_key_server=False)

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    # wait for it to go through
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    print "wait for confirmation"
    time.sleep(10)

    bar_profile_delete_key_id = None
    if 'error' in res:
        res['test'] = 'Failed to create deletable bar.test account key'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return
    else:
        key_names['bar.test'].append( res )
        bar_profile_delete_key_id = res['key_id']

    # add immutable app keys, which we can delete
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] ) 
    res = ysi_gpg.gpg_app_create_key( "foo.test", "immutable_delete", "foo_test_deleted_immutable_secmsg_key", immutable=True,
                                                proxy=test_proxy, wallet_keys=wallet_keys, config_dir=testlib.get_working_dir(**kw) )

    foo_immutable_delete_key_id = None
    if 'error' in res:
        res['test'] = 'Failed to create deletable foo.test immutable app key'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return
    else:
        key_names['foo.test'].append( res )
        foo_immutable_delete_key_id = res['key_id']

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    # wait for it to go through
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    print "wait for confirmation"
    time.sleep(10)

    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys_2['payment_privkey'], wallet_keys_2['owner_privkey'], wallet_keys_2['data_privkey'] ) 
    res = ysi_gpg.gpg_app_create_key( "bar.test", "immutable_delete", "bar_test_deleted_immutable_secmsg_key", immutable=True,
                                                proxy=test_proxy, wallet_keys=wallet_keys_2, config_dir=testlib.get_working_dir(**kw) )
    
    bar_immutable_delete_key_id = None
    if 'error' in res:
        res['test'] = 'Failed to create deletable bar.test immutable app key'
        print json.dumps(res, indent=4, sort_keys=True )
        error = True
        return
    else:
        key_names['bar.test'].append( res )
        bar_immutable_delete_key_id = res['key_id']

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    # wait for it to go through
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    print "wait for confirmation"
    time.sleep(10)

    # add mutable app keys which we can delete
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] ) 
    res = ysi_gpg.gpg_app_create_key( "foo.test", "mutable_delete", "foo_test_deleted_mutable_secmsg_key",
                                                proxy=test_proxy, wallet_keys=wallet_keys, config_dir=testlib.get_working_dir(**kw) )

    foo_mutable_delete_key_id = None
    if 'error' in res:
        res['test'] = 'Failed to create deletable mutable foo.test app key'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return
    else:
        key_names['foo.test'].append( res )
        foo_mutable_delete_key_id = res['key_id']

    testlib.next_block( **kw )
    
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys_2['payment_privkey'], wallet_keys_2['owner_privkey'], wallet_keys_2['data_privkey'] ) 
    res = ysi_gpg.gpg_app_create_key( "bar.test", "mutable_delete", "bar_test_deleted_mutable_secmsg_key",
                                                proxy=test_proxy, wallet_keys=wallet_keys_2, config_dir=testlib.get_working_dir(**kw) )

    bar_mutable_delete_key_id = None
    if 'error' in res:
        res['test'] = 'Failed to create deletable mutable bar.test app key'
        print json.dumps(res, indent=4, sort_keys=True )
        error = True
        return
    else:
        key_names['bar.test'].append( res )
        bar_mutable_delete_key_id = res['key_id']

    testlib.next_block( **kw )

    # delete profile keys
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] ) 
    res = ysi_gpg.gpg_profile_delete_key( "foo.test", foo_profile_delete_key_id, proxy=test_proxy, wallet_keys=wallet_keys )
    if 'error' in res:
        res['test'] = 'Failed to create deletable account foo.test profile key'
        print json.dumps(res, indent=4, sort_keys=True )
        error = True
        return

    testlib.next_block( **kw )
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys_2['payment_privkey'], wallet_keys_2['owner_privkey'], wallet_keys_2['data_privkey'] ) 
    res = ysi_gpg.gpg_profile_delete_key( "bar.test", bar_profile_delete_key_id, proxy=test_proxy, wallet_keys=wallet_keys_2 )
    if 'error' in res:
        res['test'] = 'Failed to create deletable account bar.test profile key'
        print json.dumps(res, indent=4, sort_keys=True )
        error = True
        return 

    # delete immutable app keys 
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] ) 
    res = ysi_gpg.gpg_app_delete_key( "foo.test", "immutable_delete", "foo_test_deleted_immutable_secmsg_key", 
                                            immutable=True, proxy=test_proxy, wallet_keys=wallet_keys, config_dir=testlib.get_working_dir(**kw))

    if 'error' in res:
        res['test'] = 'Failed to create deletable foo.test immutable app key'
        print json.dumps(res, indent=4, sort_keys=True )
        error = True
        return 

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    # wait for it to go through
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    print "wait for confirmation"
    time.sleep(10)

    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys_2['payment_privkey'], wallet_keys_2['owner_privkey'], wallet_keys_2['data_privkey'] ) 
    res = ysi_gpg.gpg_app_delete_key( "bar.test", "immutable_delete", "bar_test_deleted_immutable_secmsg_key",
                                            immutable=True, proxy=test_proxy, wallet_keys=wallet_keys_2, config_dir=testlib.get_working_dir(**kw))

    if 'error' in res:
        res['test'] = 'Failed to create deletable bar.test immutable app key'
        print json.dumps(res, indent=4, sort_keys=True )
        error = True
        return 

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    # wait for it to go through
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    print "wait for confirmation"
    time.sleep(10)

    # delete mutable app keys
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] ) 
    res = ysi_gpg.gpg_app_delete_key( "foo.test", "mutable_delete", "foo_test_deleted_mutable_secmsg_key",
                                            proxy=test_proxy, wallet_keys=wallet_keys, config_dir=testlib.get_working_dir(**kw))

    if 'error' in res:
        res['test'] = 'Failed to create deletable foo.test mutable app key'
        print json.dumps(res, indent=4, sort_keys=True )
        error = True 
        return 

    testlib.next_block( **kw )
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys_2['payment_privkey'], wallet_keys_2['owner_privkey'], wallet_keys_2['data_privkey'] ) 
    res = ysi_gpg.gpg_app_delete_key( "bar.test", "mutable_delete", "bar_test_deleted_mutable_secmsg_key",
                                            proxy=test_proxy, wallet_keys=wallet_keys_2, config_dir=testlib.get_working_dir(**kw))

    if 'error' in res:
        res['test'] = 'Failed to create deletable bar.test mutable app key'
        print json.dumps(res, indent=4, sort_keys=True )
        error = True 
        return 

    testlib.next_block( **kw )
 
    gpghome = testlib.gpg_key_dir(**kw)
Esempio n. 10
0
def scenario(wallets, **kw):

    global synchronized, value_hash

    import ysi_integration_tests.atlas_network as atlas_network

    testlib.ysi_namespace_preorder("test", wallets[1].addr, wallets[0].privkey)
    testlib.next_block(**kw)

    testlib.ysi_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.ysi_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

    testlib.ysi_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.next_block(**kw)

    testlib.ysi_name_register("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.next_block(**kw)

    # set up RPC daemon
    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy(test_proxy)
    wallet_keys = ysi_client.make_wallet_keys(
        owner_privkey=wallets[3].privkey,
        data_privkey=wallets[4].privkey,
        payment_privkey=wallets[5].privkey)
    testlib.ysi_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.ysi_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.ysi_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 = ysi_client.zonefile.make_empty_zonefile(
            "foo_{}.test".format(i),
            data_pubkey,
            urls=["file:///tmp/foo_{}.test".format(i)])
        empty_zonefile_str = ysi_zones.make_zone_file(empty_zonefile)
        value_hash = ysi_client.hash_zonefile(empty_zonefile)

        res = testlib.ysi_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)

        # propagate
        res = testlib.ysi_cli_sync_zonefile('foo_{}.test'.format(i),
                                            zonefile_string=empty_zonefile_str)
        if 'error' in res:
            print json.dumps(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 = ysi_client.utils.url_to_host_port(src_hostport)
        dest_host, dest_port = ysi_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(
        atlas_nodes, atlas_topology, {},
        os.path.join(testlib.working_dir(**kw), "atlas_network"))
    atlas_network.atlas_network_start(network_des, drop_probability=churn_drop)

    print "Waiting 120 seconds for the altas peers to catch up"
    time.sleep(120.0)

    # wait at most 60 seconds for atlas network to converge
    synchronized = False
    for i in xrange(0, 60):
        atlas_network.atlas_print_network_state(network_des)
        if atlas_network.atlas_network_is_synchronized(
                network_des,
                testlib.last_block(**kw) - 1, 1):
            print "Synchronized!"
            synchronized = True
            break

        else:
            time.sleep(1.0)

    # shut down
    atlas_network.atlas_network_stop(network_des)
    return synchronized
def scenario(wallets, **kw):

    global datasets, zonefile_hashes, put_result, last_hash

    testlib.ysi_namespace_preorder("test", wallets[1].addr, wallets[0].privkey)
    testlib.next_block(**kw)

    testlib.ysi_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.ysi_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

    testlib.ysi_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.next_block(**kw)

    testlib.ysi_name_register("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.next_block(**kw)

    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy(test_proxy)

    wallet_keys = ysi_client.make_wallet_keys(
        owner_privkey=wallets[3].privkey,
        data_privkey=wallets[4].privkey,
        payment_privkey=wallets[5].privkey)

    # migrate profile
    res = testlib.migrate_profile("foo.test",
                                  proxy=test_proxy,
                                  wallet_keys=wallet_keys)
    if 'error' in res:
        res['test'] = 'Failed to initialize foo.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    testlib.next_block(**kw)

    testlib.ysi_client_set_wallet("0123456789abcdef",
                                  wallet_keys['payment_privkey'],
                                  wallet_keys['owner_privkey'],
                                  wallet_keys['data_privkey'])

    res = testlib.start_api("0123456789abcdef")
    if 'error' in res:
        print 'failed to start API: {}'.format(res)
        return False

    put_result = ysi_client.put_immutable("foo.test",
                                          "hello_world_1",
                                          json.dumps(datasets[0],
                                                     sort_keys=True),
                                          proxy=test_proxy,
                                          wallet_keys=wallet_keys)
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)
        return False

    testlib.expect_atlas_zonefile(put_result['zonefile_hash'])
    zonefile_hashes.append(put_result['immutable_data_hash'])

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    # wait for confirmation
    for i in xrange(0, 12):
        testlib.next_block(**kw)
    print "waiting for confirmation"
    time.sleep(10)

    put_result = ysi_client.put_immutable("foo.test",
                                          "hello_world_2",
                                          json.dumps(datasets[1],
                                                     sort_keys=True),
                                          proxy=test_proxy,
                                          wallet_keys=wallet_keys)
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)
        return False

    testlib.expect_atlas_zonefile(put_result['zonefile_hash'])
    zonefile_hashes.append(put_result['immutable_data_hash'])

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    # wait for confirmation
    for i in xrange(0, 12):
        testlib.next_block(**kw)
    print "waiting for confirmation"
    time.sleep(10)

    put_result = ysi_client.put_immutable("foo.test",
                                          "hello_world_3",
                                          json.dumps(datasets[2],
                                                     sort_keys=True),
                                          proxy=test_proxy,
                                          wallet_keys=wallet_keys)
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)
        return False

    testlib.expect_atlas_zonefile(put_result['zonefile_hash'])
    zonefile_hashes.append(put_result['immutable_data_hash'])

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    # wait for confirmation
    for i in xrange(0, 12):
        testlib.next_block(**kw)
    print "waiting for confirmation"
    time.sleep(10)

    # should succeed (name collision)
    datasets[0]['newdata'] = "asdf"
    put_result = ysi_client.put_immutable("foo.test",
                                          "hello_world_1",
                                          json.dumps(datasets[0],
                                                     sort_keys=True),
                                          proxy=test_proxy,
                                          wallet_keys=wallet_keys)
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)
        return False

    zonefile_hashes[0] = put_result['immutable_data_hash']

    testlib.expect_atlas_zonefile(put_result['zonefile_hash'])
    del datasets[0]['newdata']

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    for i in xrange(0, 12):
        testlib.next_block(**kw)
    print "waiting for confirmation"
    time.sleep(10)

    # delete everything
    for i in xrange(0, len(datasets)):
        print "delete %s" % zonefile_hashes[i]
        put_result = ysi_client.delete_immutable("foo.test",
                                                 zonefile_hashes[i],
                                                 wallet_keys=wallet_keys)
        if 'error' in put_result:
            print json.dumps(put_result, indent=4, sort_keys=True)

        testlib.expect_atlas_zonefile(put_result['zonefile_hash'])

        # tell serialization-checker that value_hash can be ignored here
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        # wait for conformation
        for i in xrange(0, 12):
            testlib.next_block(**kw)
        print "waiting for confirmation"
        time.sleep(10)

    last_hash = put_result['zonefile_hash']
def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, wallet_keychain, error, index_file_data, resource_data, sessions

    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy( test_proxy )
    
    wallet_keys_2 = ysi_client.make_wallet_keys( owner_privkey=wallets[4].privkey, data_privkey=wallets[5].privkey, payment_privkey=wallets[3].privkey )
    wallet_keys = ysi_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[5].privkey )

    wallet_keychain = {
        'foo.test': wallet_keys,
        'bar.test': wallet_keys_2,
    }

    # install wallet_keys
    testlib.ysi_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] )

    testlib.ysi_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.ysi_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.ysi_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    testlib.ysi_name_preorder( "foo.test", wallets[2].privkey, wallets[3].addr )
    testlib.ysi_name_preorder( "bar.test", wallets[3].privkey, wallets[4].addr )
    testlib.next_block( **kw )
    
    testlib.ysi_name_register( "foo.test", wallets[2].privkey, wallets[3].addr )
    testlib.ysi_name_register( "bar.test", wallets[3].privkey, wallets[4].addr )
    testlib.next_block( **kw )
   
    setup_storage_dirs(['foo.test', 'bar.test'])

    # migrate profiles 
    # BUT! make sure we store the profile for foo.test into both foo.test's and bar.test's storage directories!
    os.environ['TEST_BLOCKSTACK_TEST_DISK_ROOT'] = '/tmp/ysi-integration-test-storage-foo.test'

    res = testlib.migrate_profile( "foo.test", proxy=test_proxy, wallet_keys=wallet_keys )
    if 'error' in res:
        res['test'] = 'Failed to initialize foo.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    shutil.copy("/tmp/ysi-integration-test-storage-foo.test/mutable/foo.test", "/tmp/ysi-integration-test-storage-bar.test/mutable/foo.test")
    
    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    testlib.next_block(**kw)

    # store zonefile
    res = ysi_client.proxy.put_zonefiles("localhost:16264", [base64.b64encode(res['zonefile_txt'])])
    if 'error' in res:
        print 'failed to store zonefile for foo.test: {}'.format(res)
        return False

    # BUT! make sure we store the profile for bar.test into both foo.test's and bar.test's storage directories!
    os.environ['TEST_BLOCKSTACK_TEST_DISK_ROOT'] = '/tmp/ysi-integration-test-storage-bar.test'

    res = testlib.migrate_profile( "bar.test", proxy=test_proxy, wallet_keys=wallet_keys_2 )
    if 'error' in res:
        res['test'] = 'Failed to initialize bar.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    shutil.copy("/tmp/ysi-integration-test-storage-bar.test/mutable/bar.test", "/tmp/ysi-integration-test-storage-foo.test/mutable/bar.test")

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    testlib.next_block(**kw)

    # store zonefile
    res = ysi_client.proxy.put_zonefiles("localhost:16264", [base64.b64encode(res['zonefile_txt'])])
    if 'error' in res:
        print 'failed to store zonefile for bar.test: {}'.format(res)
        return False

    res = testlib.start_api("0123456789abcdef")
    if 'error' in res:
        print 'failed to start API for foo.test: {}'.format(res)
        return False

    target_datastore('foo.test')

    # instantiate foo.test's test driver
    res = testlib.ysi_REST_call('POST', '/v1/node/drivers/storage/test?index=1&force=1', None, api_pass='******')
    if 'error' in res or res['http_status'] != 200:
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    res = testlib.ysi_cli_put_account("foo.test", "test", 'storage', "test:///index/index.manifest?diskroot=/tmp/ysi-integration-test-storage-foo.test",
                                             None, wallet_keys=wallet_keys )
    if 'error' in res:
        res['test'] = 'Failed to create foo.test account'
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    os.makedirs('/tmp/ysi-integration-test-storage/mutable')
    os.makedirs('/tmp/ysi-integration-test-storage/immutable')

    shutil.copy("/tmp/ysi-integration-test-storage-foo.test/mutable/foo.test", "/tmp/ysi-integration-test-storage-bar.test/mutable/foo.test")
    shutil.copy("/tmp/ysi-integration-test-storage-foo.test/mutable/foo.test", "/tmp/ysi-integration-test-storage/mutable/foo.test")

    # link test account for bar.test
    # BUT! make sure we store the profile for bar.test into foo.test's and bar.test's storage directories!
    target_datastore('bar.test')

    # instantiate bar.test's test driver 
    res = testlib.ysi_REST_call('POST', '/v1/node/drivers/storage/test?index=1&force=1', None, api_pass='******')
    if 'error' in res or res['http_status'] != 200:
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    res = testlib.ysi_cli_put_account("bar.test", "test", 'storage', "test:///index/index.manifest?diskroot=/tmp/ysi-integration-test-storage-bar.test",
                                             None, wallet_keys=wallet_keys_2 )
    if 'error' in res:
        res['test'] = 'Failed to create bar.test account'
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    shutil.copy("/tmp/ysi-integration-test-storage-bar.test/mutable/bar.test", "/tmp/ysi-integration-test-storage-foo.test/mutable/bar.test")
    shutil.copy("/tmp/ysi-integration-test-storage-bar.test/mutable/bar.test", "/tmp/ysi-integration-test-storage/mutable/bar.test")

    # restore...we'll set up foo.test next
    res = testlib.ysi_test_setenv("TEST_BLOCKSTACK_TEST_DISK_ROOT", "/tmp/ysi-integration-test-storage-foo.test")
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    # get datastore keys...
    foo_datastore_pk = keylib.ECPrivateKey(wallets[-1].privkey).to_hex()
    datastore_id_res = testlib.ysi_cli_datastore_get_id( foo_datastore_pk )
    foo_datastore_id = datastore_id_res['datastore_id']

    bar_datastore_pk = keylib.ECPrivateKey(wallets[-2].privkey).to_hex()
    datastore_id_res = testlib.ysi_cli_datastore_get_id( bar_datastore_pk )
    bar_datastore_id = datastore_id_res['datastore_id']

    # activate foo.test 
    res = activate_account("foo.test", foo_datastore_pk)
    if not res:
        print 'failed to start API for bar.test: {}'.format(res)
        return False

    # set up foo.test's datastore 
    res = setup_datastore(wallets[-1].privkey, "foo.test", 1)
    if not res:
        print 'failed to setup foo.test datastore'
        return False

    # activate bar.test 
    res = activate_account("bar.test", bar_datastore_pk)
    if not res:
        print 'failed to start API for bar.test: {}'.format(res)
        return False

    # make *absolutely certain* that the test driver does not load data from
    # foo.test's or bar.test's storage directories.  We want to verify that we can look up
    # the index manifest URLs from the profile
    target_datastore(None)

    print "\n\nbar.test tries to read foo.test's datastore {}\n\n".format(foo_datastore_id)
    res = read_datastore(foo_datastore_id, "foo.test", 1)
    if not res:
        print 'failed to read foo.test datastore {}'.format(foo_datastore_id)
        return False

    # set up bar.test's files 
    res = setup_datastore(wallets[-2].privkey, 'bar.test', 2)
    if not res:
        print 'failed to setup bar.test datastore'
        return False

    # activate foo.test
    res = activate_account("foo.test", foo_datastore_pk)
    if not res:
        print 'failed to start API for foo.test: {}'.format(res)
        return False

    # make *absolutely certain* that the test driver does not load data from
    # foo.test's or bar.test's storage directories.  We want to verify that we can look up
    # the index manifest URLs from the profile
    target_datastore(None)

    # try to read all of bar.test's files
    print "\n\nfoo.test tries to read bar.test's datastore {}\n\n".format(bar_datastore_id)
    res = read_datastore(bar_datastore_id, 'bar.test', 2)
    if not res:
        print 'failed to read bar.test datastore {}'.format(bar_datastore_id)
        return False

    # re-target foo.test's datastore
    target_datastore('foo.test')

    # have foo.test write new files 
    print '\n\nupdate foo.test datastore\n\n'
    res = write_datastore('foo.test', foo_datastore_pk, 3)
    if not res:
        print 'failed to update foo.test datastore {}'.format(foo_datastore_id)
        return False

    # activate bar.test
    res = activate_account("bar.test", bar_datastore_pk)
    if not res:
        print 'failed to start API for bar.test: {}'.format(res)
        return False

    # make *absolutely certain* that the test driver does not load data from
    # foo.test's or bar.test's storage directories.  We want to verify that we can look up
    # the index manifest URLs from the profile
    target_datastore(None)

    # get foo.test's new files 
    res = read_datastore(foo_datastore_id, 'foo.test', 3)
    if not res:
        print 'failed to read new files from foo.test'
        return False

    # re-target bar.test's datastore
    target_datastore('bar.test')

    # have bar write some new files 
    print '\n\nupdate bar.test datastore\n\n'
    res = write_datastore('bar.test', bar_datastore_pk, 4)
    if not res:
        print 'failed ot update bar.test datastore {}'.format(bar_datastore_id)
        return False

    # activate foo.test
    res = activate_account("foo.test", foo_datastore_pk)
    if not res:
        print 'failed to start API for foo.test: {}'.format(res)
        return False

    # delete foo's files 
    print '\n\ndelete foo.test files\n\n'
    res = clear_datastore_files('foo.test', foo_datastore_pk)
    if not res:
        print 'failed to clear datastore {} for foo.test'.format(foo_datastore_id)
        return False

    # activate bar.test
    res = activate_account("bar.test", bar_datastore_pk)
    if not res:
        print 'failed to start API for bar.test: {}'.format(res)
        return False

    # make *absolutely certain* that the test driver does not load data from
    # foo.test's or bar.test's storage directories.  We want to verify that we can look up
    # the index manifest URLs from the profile
    target_datastore(None)

    # verify that foo's files are gone 
    res = check_datastore_files_absent(foo_datastore_id, 'foo.test')
    if not res:
        print 'failed to verify that foo.test datastore {} is devoid of files'.format(foo_datastore_id)
        return False

    # re-target bar.test's datastore
    target_datastore('bar.test')

    # clear bar.test's files
    print '\n\ndelete bar.test files\n\n'
    res = clear_datastore_files('bar.test', bar_datastore_pk)
    if not res:
        print 'failed to clear datastore {} for bar.test'.format(bar_datastore_id)
        return False

    # activate foo.test
    res = activate_account("foo.test", foo_datastore_pk)
    if not res:
        print 'failed to start API for foo.test: {}'.format(res)
        return False

    # make *absolutely certain* that the test driver does not load data from
    # foo.test's or bar.test's storage directories.  We want to verify that we can look up
    # the index manifest URLs from the profile
    target_datastore(None)

    # verify that bar's files are gone 
    res = check_datastore_files_absent(bar_datastore_id, 'bar.test')
    if not res:
        print 'failed to verify that bar.test datastore {} is devoid of files'.format(bar_datastore_id)
        return False

    # re-target foo.test's datastore
    target_datastore("foo.test")

    # clear foo's directories 
    res = clear_datastore_directories('foo.test', foo_datastore_pk)
    if not res:
        print 'failed to clear foo.test datastore {} of directories'.format(foo_datastore_id)
        return False

    # activate bar.test
    res = activate_account("bar.test", bar_datastore_pk)
    if not res:
        print 'failed to start API for bar.test: {}'.format(res)
        return False

    # make *absolutely certain* that the test driver does not load data from
    # foo.test's or bar.test's storage directories.  We want to verify that we can look up
    # the index manifest URLs from the profile
    target_datastore(None)

    # verify that foo's directories are gone 
    res = check_datastore_directories_absent(foo_datastore_id, "foo.test")
    if not res:
        print 'failed to verify that foo.test datastore {} is devoid of directories'.format(foo_datastore_id)
        return False

    # re-target bar.test's datastore
    target_datastore('bar.test')

    # clear bar's directories
    res = clear_datastore_directories('bar.test', bar_datastore_pk)
    if not res:
        print 'failed to clear bar.test datastore {} of directories'.format(bar_datastore_id)
        return False

    # activate foo.test
    res = activate_account('foo.test', foo_datastore_pk)
    if not res:
        print 'failed to start API for foo.test: {}'.format(res)
        return False

    # make *absolutely certain* that the test driver does not load data from
    # foo.test's or bar.test's storage directories.  We want to verify that we can look up
    # the index manifest URLs from the profile
    target_datastore(None)

    # verify that bar's directories are gone
    res = check_datastore_directories_absent(bar_datastore_id, "bar.test")
    if not res:
        print 'failed to verify that bar.test datastore {} is devoid of directories'.format(bar_datastore_id)
        return False

    # root should be empty in both cases
    print 'listdir {} (bar.test)'.format('/')
    res = testlib.ysi_cli_datastore_listdir( 'bar.test', bar_datastore_id, '/', data_pubkeys=get_data_pubkeys('bar.test'))
    if 'error' in res:
        print 'failed to listdir / on bar.test: {}'.format(res['error'])
        return False

    if len(res['children'].keys()) > 0:
        print 'root still has children: {}'.format(res['children'].keys())
        return False

    # activate bar.test
    res = activate_account('bar.test', bar_datastore_pk)
    if not res:
        print 'failed to start API for foo.test: {}'.format(res)
        return False

    print 'listdir {} (foo.test)'.format('/')
    res = testlib.ysi_cli_datastore_listdir( 'foo.test', foo_datastore_id, '/', data_pubkeys=get_data_pubkeys('foo.test'))
    if 'error' in res:
        print 'failed to listdir / on foo.test: {}'.format(res['error'])
        return False

    if len(res['children'].keys()) > 0:
        print 'root still has children: {}'.format(res['children'].keys())
        return False

    testlib.next_block( **kw )
def scenario( wallets, **kw ):

    global put_result, wallet_keys, datasets, zonefile_hash, dataset_change

    wallet = testlib.ysi_client_initialize_wallet( "0123456789abcdef", wallets[2].privkey, wallets[3].privkey, wallets[4].privkey )
    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy( test_proxy )
    wallet_keys = ysi_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey )

    testlib.ysi_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.ysi_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.ysi_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    resp = testlib.ysi_cli_register( "foo.test", "0123456789abcdef" )
    if 'error' in resp:
        print >> sys.stderr, json.dumps(resp, indent=4, sort_keys=True)
        return False
   
    # wait for the preorder to get confirmed
    for i in xrange(0, 12):
        testlib.next_block( **kw )

    # wait for the poller to pick it up
    print >> sys.stderr, "Waiting for the backend to submit the register"
    time.sleep(10)

    # wait for the register to get confirmed 
    for i in xrange(0, 12):
        testlib.next_block( **kw )

    print >> sys.stderr, "Waiting for the backend to acknowledge registration"
    time.sleep(10)

    # wait for initial update to get confirmed 
    for i in xrange(0, 12):
        # tell serialization-checker that value_hash can be ignored here
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
    
        testlib.next_block( **kw )

    print >> sys.stderr, "Waiting for the backend to acknowledge update"
    time.sleep(10)

    # wait for zonefile/profile replication
    for i in xrange(0, 12):
        testlib.next_block( **kw )

    print >> sys.stderr, "Waiting for the backend to replicate zonefile and profile"
    time.sleep(10)


    # make a few accounts
    res = testlib.ysi_cli_put_account("foo.test", "serviceFoo", "serviceFooID", "foo://bar.com", "0123456789abcdef", extra_data='foofield=foo!', wallet_keys=wallet_keys)
    if 'error' in res:
        res['test'] = 'Failed to create foo.test serviceFoo account'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

    time.sleep(2)

    res = testlib.ysi_cli_put_account("foo.test", "serviceBar", "serviceBarID", "bar://baz.com", "0123456789abcdef", extra_data='barfield=bar!', wallet_keys=wallet_keys)
    if 'error' in res:
        res['test'] = 'Failed to create foo.test serviceBar account'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

    time.sleep(2)

    # put some data
    put_result = testlib.ysi_cli_put_mutable( "foo.test", "hello_world_1", json.dumps(datasets[0]), password="******")
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)
        return False

    testlib.next_block( **kw )

    time.sleep(2)

    put_result = testlib.ysi_cli_put_mutable( "foo.test", "hello_world_2", json.dumps(datasets[1]), password="******", \
                                                     storage_drivers=['ysi_server'], storage_drivers_exclusive=True)
    
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)
        return False

    time.sleep(2)

    put_result = testlib.ysi_cli_put_mutable( "foo.test", "hello_world_3", json.dumps(datasets[2]), password="******", \
                                                     storage_drivers=['ysi_server'], storage_drivers_exclusive=True)

    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)
        return False

    time.sleep(2)

    # increment data version too
    datasets[0]['buf'] = []
    for i in xrange(0, 5):
        datasets[0]["dataset_change"] = dataset_change
        datasets[0]['buf'].append(i)

        put_result = testlib.ysi_cli_put_mutable( "foo.test", "hello_world_1", json.dumps(datasets[0]), password="******", \
                                                         storage_drivers=['ysi_server'], storage_drivers_exclusive=True)

        if 'error' in put_result:
            print json.dumps(put_result, indent=4, sort_keys=True )
            return False

        time.sleep(2)

    testlib.next_block( **kw )
def scenario(wallets, **kw):

    global datasets, put_result, legacy_profile, data_history_1, data_history_2, data_history_3

    testlib.ysi_namespace_preorder("test", wallets[1].addr, wallets[0].privkey)
    testlib.next_block(**kw)

    testlib.ysi_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.ysi_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

    testlib.ysi_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.next_block(**kw)

    testlib.ysi_name_register("foo.test", wallets[2].privkey, wallets[3].addr)
    testlib.next_block(**kw)

    # empty data
    testlib.ysi_name_update("foo.test", "00" * 20, wallets[3].privkey)
    data_history_1.append("missing zonefile")
    data_history_2.append("missing zonefile")
    data_history_3.append("missing zonefile")

    testlib.next_block(**kw)

    # set up legacy profile hash
    legacy_txt = json.dumps(legacy_profile, sort_keys=True)
    legacy_hash = virtualchain.lib.hashing.hex_hash160(legacy_txt)

    result = testlib.ysi_name_update("foo.test", legacy_hash,
                                     wallets[3].privkey)
    data_history_1.append("non-standard zonefile")
    data_history_2.append("non-standard zonefile")
    data_history_3.append("non-standard zonefile")
    testlib.next_block(**kw)

    rc = ysi_client.storage.put_immutable_data(legacy_txt,
                                               result['transaction_hash'],
                                               data_hash=legacy_hash)
    assert rc is not None

    # put immutable data
    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy(test_proxy)
    wallet_keys = ysi_client.make_wallet_keys(
        owner_privkey=wallets[3].privkey,
        data_privkey=wallets[4].privkey,
        payment_privkey=wallets[5].privkey)

    # migrate profile
    res = testlib.migrate_profile("foo.test",
                                  proxy=test_proxy,
                                  wallet_keys=wallet_keys)
    if 'error' in res:
        res['test'] = 'Failed to initialize foo.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    testlib.next_block(**kw)
    data_history_1.append("data not defined")
    data_history_2.append("data not defined")
    data_history_3.append("data not defined")

    testlib.ysi_client_set_wallet("0123456789abcdef",
                                  wallet_keys['payment_privkey'],
                                  wallet_keys['owner_privkey'],
                                  wallet_keys['data_privkey'])

    res = testlib.start_api("0123456789abcdef")
    if 'error' in res:
        print 'failed to start API: {}'.format(res)
        return False

    put_result = ysi_client.put_immutable("foo.test",
                                          "hello_world_1",
                                          json.dumps(datasets[0],
                                                     sort_keys=True),
                                          proxy=test_proxy,
                                          wallet_keys=wallet_keys)
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)

    testlib.expect_atlas_zonefile(put_result['zonefile_hash'])

    data_history_1.append(put_result['immutable_data_hash'])
    data_history_2.append("data not defined")
    data_history_3.append("data not defined")

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    # wait for confirmation
    for i in xrange(0, 12):
        testlib.next_block(**kw)
    print "waiting for confirmation"
    time.sleep(10)

    put_result = ysi_client.put_immutable("foo.test",
                                          "hello_world_2",
                                          json.dumps(datasets[1],
                                                     sort_keys=True),
                                          proxy=test_proxy,
                                          wallet_keys=wallet_keys)
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)

    testlib.expect_atlas_zonefile(put_result['zonefile_hash'])

    data_history_1.append(data_history_1[-1])
    data_history_2.append(put_result['immutable_data_hash'])
    data_history_3.append("data not defined")

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    # wait for confirmation
    for i in xrange(0, 12):
        testlib.next_block(**kw)
    print "waiting for confirmation"
    time.sleep(10)

    put_result = ysi_client.put_immutable("foo.test",
                                          "hello_world_3",
                                          json.dumps(datasets[2],
                                                     sort_keys=True),
                                          proxy=test_proxy,
                                          wallet_keys=wallet_keys)
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)

    testlib.expect_atlas_zonefile(put_result['zonefile_hash'])

    data_history_1.append(data_history_1[-1])
    data_history_2.append(data_history_2[-1])
    data_history_3.append(put_result['immutable_data_hash'])

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    testlib.next_block(**kw)

    # wait for confirmation
    for i in xrange(0, 12):
        testlib.next_block(**kw)
    print "waiting for confirmation"
    time.sleep(10)

    # overwrite
    datasets[0]['newdata'] = "asdf"
    put_result = ysi_client.put_immutable("foo.test",
                                          "hello_world_3",
                                          json.dumps(datasets[0],
                                                     sort_keys=True),
                                          proxy=test_proxy,
                                          wallet_keys=wallet_keys)
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)

    testlib.expect_atlas_zonefile(put_result['zonefile_hash'])

    data_history_1.append(data_history_1[-1])
    data_history_2.append(data_history_2[-1])
    data_history_3.append(put_result['immutable_data_hash'])

    del datasets[0]['newdata']

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    # wait for confirmation
    for i in xrange(0, 12):
        testlib.next_block(**kw)
    print "waiting for confirmation"
    time.sleep(10)