Example #1
0
def scenario(wallets, **kw):

    global zonefile_hash

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

    testlib.blockstack_namespace_reveal(
        "test", wallets[1].addr, 52595, 250, 4,
        [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10,
        wallets[0].privkey)
    testlib.next_block(**kw)

    testlib.blockstack_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

    wallet = testlib.blockstack_client_initialize_wallet(
        "0123456789abcdef", wallets[2].privkey, wallets[3].privkey,
        wallets[5].privkey)
    resp = testlib.blockstack_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 10 seconds for the backend to submit the register"
    time.sleep(15)

    # wait for the register to get confirmed
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block(**kw)

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

    # wait for update to get confirmed
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block(**kw)

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

    # send an update, changing the zonefile
    data_pubkey = wallet['data_pubkey']
    zonefile = blockstack_client.zonefile.make_empty_zonefile(
        "foo.test", data_pubkey)
    blockstack_client.user.put_immutable_data_zonefile(
        zonefile,
        "testdata",
        blockstack_client.get_data_hash("testdata"),
        data_url="file:///testdata")
    zonefile_json = json.dumps(zonefile)

    resp = testlib.blockstack_cli_update("foo.test", zonefile_json,
                                         "0123456789abcdef")

    if 'error' in resp:
        print >> sys.stderr, "update error: %s" % resp['error']
        return False

    zonefile_hash = resp['zonefile_hash']

    # wait for it to go through
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block(**kw)

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

    # transfer to a new address
    resp = testlib.blockstack_cli_transfer("foo.test", wallets[4].addr,
                                           "0123456789abcdef")

    if 'error' in resp:
        print >> sys.stderr, "transfer error: %s" % resp['error']
        return False

    # wait for it to go through
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block(**kw)

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

    # regenerate the wallet, with the new owner address
    wallet = testlib.blockstack_client_set_wallet("0123456789abcdef",
                                                  wallets[5].privkey,
                                                  wallets[4].privkey,
                                                  wallets[5].privkey)

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

    # send another update, changing the zonefile again
    # pay for it using the same payment address
    zonefile = blockstack_client.zonefile.make_empty_zonefile(
        "foo.test", new_data_pubkey)
    blockstack_client.user.put_immutable_data_zonefile(
        zonefile,
        "testdata",
        blockstack_client.get_data_hash("testdata"),
        data_url="file:///testdata")
    zonefile_json = json.dumps(zonefile)

    resp = testlib.blockstack_cli_update("foo.test", zonefile_json,
                                         "0123456789abcdef")

    if 'error' in resp:
        print >> sys.stderr, "update error: %s" % resp['error']
        return False

    zonefile_hash = resp['zonefile_hash']

    # wait for it to go through
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block(**kw)

    print >> sys.stderr, "Waiting 10 seconds for the backend to acknowedge the update"
    time.sleep(15)
Example #2
0
def scenario( wallets, **kw ):

    global zonefile_hash, final_balance, new_expire_block

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

    testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    wallet = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[2].privkey, wallets[3].privkey, wallets[4].privkey )
    resp = testlib.blockstack_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 10 seconds for the backend to submit the register"
    time.sleep(10)


    # wait for the register to get confirmed
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block( **kw )

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

    # wait for initial update to get confirmed
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block( **kw )

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

    # what's the name's renewal block?
    proxy = testlib.make_proxy()
    res = blockstack_client.get_name_blockchain_record( "foo.test", proxy=proxy )
    if 'error' in res:
        print >> sys.stderr, json.dumps(res, indent=4, sort_keys=True)
        return False

    old_expire_block = res['expire_block']

    # send an update, changing the zonefile
    data_pubkey = wallet['data_pubkey']
    zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo.test", data_pubkey )
    blockstack_client.user.put_immutable_data_zonefile( zonefile, "testdata", blockstack_client.get_data_hash("testdata"), data_url="file:///testdata")
    zonefile_json = json.dumps(zonefile)

    resp = testlib.blockstack_cli_update( "foo.test", zonefile_json, "0123456789abcdef" )

    if 'error' in resp:
        print >> sys.stderr, "update error: %s" % resp['error']
        return False

    zonefile_hash = resp['zonefile_hash']

    # wait for it to go through
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block( **kw )

    print >> sys.stderr, "Waiting 10 seconds for the backend to acknowedge the update"
    time.sleep(10)
    # wait for it to go through
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block( **kw )

    # renew it
    resp = testlib.blockstack_cli_renew( "foo.test", "0123456789abcdef" )
    if 'error' in resp:
        print >> sys.stderr, "Renewal request failed:\n%s" % json.dumps(resp, indent=4, sort_keys=True)
        return False

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

    # wait for it to go through
    for i in xrange(0, 6):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block( **kw )

    # verify that it's in the queue
    queue_state = testlib.blockstack_cli_info()
    if 'error' in queue_state:
        print json.dumps(queue_state)
        return False

    if not queue_state.has_key('queues'):
        print 'no queues'
        print json.dumps(queue_state)
        return False

    if not queue_state['queues'].has_key('renew'):
        print 'no renew queue'
        print json.dumps(queue_state)
        return False

    if len(queue_state['queues']['renew']) != 1:
        print 'wrong renew state'
        print json.dumps(queue_state)
        return False

    if queue_state['queues']['renew'][0]['name'] != 'foo.test':
        print 'wrong name'
        print json.dumps(queue_state)
        return False

    # wait for it to go through
    for i in xrange(0, 6):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block( **kw )


    proxy = testlib.make_proxy()
    res = blockstack_client.get_name_blockchain_record( "foo.test", proxy=proxy )
    if 'error' in res:
        print >> sys.stderr, json.dumps(res, indent=4, sort_keys=True)
        return False


    new_expire_block = res['expire_block']
    if old_expire_block >= new_expire_block + 12:
        # didn't go through
        print >> sys.stderr, "Renewal didn't go through: %s --> %s" % (old_expire_block, new_expire_block)
        return False

    if res['op'] != blockstack_client.config.NAME_REGISTRATION + ":":
        print >> sys.stderr, "Renewal didn't go through (last op is %s)" % res['op']
        error = True
        return False

    final_balance = testlib.getbalance( wallets[2].addr )
def scenario( wallets, **kw ):

    global zonefile_hash

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

    testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    wallet = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[2].privkey, wallets[3].privkey, wallets[4].privkey )
    resp = testlib.blockstack_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 10 seconds for the backend to submit the register"
    time.sleep(10)


    # wait for the register to get confirmed 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

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

    # wait for initial update to get confirmed 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

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

    # what's the name's renewal block?
    proxy = testlib.make_proxy()
    res = blockstack_client.get_name_blockchain_record( "foo.test", proxy=proxy )
    if 'error' in res:
        print >> sys.stderr, json.dumps(res, indent=4, sort_keys=True)
        return False
    
    old_expire_block = res['expire_block']

    # send an update, changing the zonefile
    data_pubkey = wallet['data_pubkey']
    zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo.test", data_pubkey )
    blockstack_client.user.put_immutable_data_zonefile( zonefile, "testdata", blockstack_client.get_data_hash("testdata"), data_url="file:///testdata")
    zonefile_json = json.dumps(zonefile)

    resp = testlib.blockstack_cli_update( "foo.test", zonefile_json, "0123456789abcdef" )
    
    if 'error' in resp:
        print >> sys.stderr, "update error: %s" % resp['error']
        return False

    zonefile_hash = resp['zonefile_hash']
    
    # wait for it to go through 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

    print >> sys.stderr, "Waiting 10 seconds for the backend to acknowedge the update"
    time.sleep(10)
    # wait for it to go through 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

    # revoke it 
    resp = testlib.blockstack_cli_revoke( "foo.test", "0123456789abcdef" )
    if 'error' in resp:
        print >> sys.stderr, "Revoke request failed:\n%s" % json.dumps(resp, indent=4, sort_keys=True)
        return False

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

    # wait for it to go through 
    for i in xrange(0, 12):
        testlib.next_block( **kw )
def scenario( wallets, **kw ):

    global synchronized, value_hash

    import blockstack_integration_tests.atlas_network as atlas_network

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

    testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

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

    # set up RPC daemon
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy( test_proxy )
    wallet_keys = blockstack_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[5].privkey )
    testlib.blockstack_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] )

    # 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 )

    time_start = int(time.time())
    
    # put the seed after the first four
    all_peers = atlas_nodes[:4] + [16264] + atlas_nodes[4:]

    def churn_drop(src_hostport, dest_hostport):
        if src_hostport is None:
            return 0.0

        src_host, src_port = blockstack_client.config.url_to_host_port( src_hostport )
        dest_host, dest_port = blockstack_client.config.url_to_host_port( dest_hostport )

        now = int(time.time())
        offset = (now - time_start) % 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 25 seconds for the altas peers to catch up"
    time.sleep(25.0)

    # make an empty zonefile
    data_pubkey = virtualchain.BitcoinPrivateKey(wallet_keys['data_privkey']).public_key().to_hex()
    empty_zonefile = blockstack_client.user.make_empty_user_zonefile( "foo.test", data_pubkey, urls=["file:///tmp/foo.test"] )
    empty_zonefile_str = json.dumps(empty_zonefile) 
    value_hash = blockstack_client.hash_zonefile( empty_zonefile )

    # propagate the zonefile
    res = testlib.blockstack_cli_update( "foo.test", empty_zonefile_str, "0123456789abcdef" )

    for i in xrange(0, 12):
        testlib.next_block( **kw )
        
    print "Waiting for zonefile propagation"
    time.sleep(10.0)

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

    global put_result, wallet_keys, legacy_profile, zonefile_hash, zonefile_hash_2, error

    wallet_keys = testlib.blockstack_client_initialize_wallet(
        "0123456789abcdef", wallets[8].privkey, wallets[3].privkey,
        wallets[4].privkey)

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

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

    testlib.blockstack_namespace_reveal(
        "test", wallets[1].addr, 52595, 250, 4,
        [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10,
        wallets[0].privkey)
    testlib.next_block(**kw)

    testlib.blockstack_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

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

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

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

    result_1 = testlib.blockstack_cli_update("foo.test", legacy_txt,
                                             '0123456789abcdef')
    if 'error' in result_1:
        print json.dumps(result_1, indent=4, sort_keys=True)
        return False

    # wait for it to go through...
    for i in xrange(0, 12):
        testlib.next_block(**kw)

    print "wait 10 seconds for update to go through"
    time.sleep(10)

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

    testlib.next_block(**kw)

    # migrate profiles to standard zonefiles
    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

    testlib.next_block(**kw)

    # give foo.test a nonstandard zonefile (as something that serializes to JSON)
    nonstandard_zonefile_json = {'nonstandard': 'true', 'error': 'nonstandard'}
    nonstandard_zonefile_txt = json.dumps(nonstandard_zonefile_json,
                                          sort_keys=True)
    nonstandard_zonefile_raw = binascii.unhexlify("".join(
        ["%02x" % i for i in xrange(0, 256)]))

    zf_data = [nonstandard_zonefile_txt, nonstandard_zonefile_raw]
    for zi in xrange(0, len(zf_data)):
        nonstandard_zonefile = zf_data[zi]

        resp = testlib.blockstack_cli_update("foo.test",
                                             nonstandard_zonefile,
                                             "0123456789abcdef",
                                             nonstandard=True)
        if 'error' in resp:
            print "failed to put nonstandard zonefile '%s'" % nonstandard_zonefile
            print json.dumps(resp, indent=4, sort_keys=True)
            return False

        testlib.expect_atlas_zonefile(resp['zonefile_hash'])

        # wait for it to take effect
        for i in xrange(0, 12):
            testlib.next_block(**kw)

        time.sleep(10)

        # getting zonefile should still work...
        resp = testlib.blockstack_cli_get_name_zonefile("foo.test",
                                                        json=True,
                                                        raw=False)
        if 'error' in resp:
            print "failed to get zonefile %s" % zi
            print json.dumps(resp, indent=4, sort_keys=True)
            return False

        if resp['zonefile'] != nonstandard_zonefile:
            print "failed to load nonstandard zonefile json"
            print "expected:\n%s\n\ngot:\n%s" % (nonstandard_zonefile,
                                                 resp['zonefile'])
            return False

        # the following should all fail
        dataplane_funcs = [
            ("lookup", lambda: testlib.blockstack_cli_lookup("foo.test")),
            ("put_immutable", lambda: testlib.blockstack_cli_put_immutable(
                "foo.test",
                "fail",
                '{"Fail": "Yes"}',
                password='******')),
            ("get_immutable",
             lambda: testlib.blockstack_cli_get_immutable("foo.test", "fail")),
            ("put_mutable", lambda: testlib.blockstack_cli_put_mutable(
                "foo.test",
                "fail",
                '{"fail": "yes"}',
                password='******')),
            ("get_mutable",
             lambda: testlib.blockstack_cli_get_mutable("foo.test", "fail")),
            ("delete_immutable",
             lambda: testlib.blockstack_cli_delete_immutable(
                 "foo.test", "00" * 32, password='******')),
            ("delete_mutable", lambda: testlib.blockstack_cli_delete_mutable(
                "foo.test", "fail", password='******'))
        ]

        for data_func_name, data_func in dataplane_funcs:
            resp = data_func()
            if 'error' not in resp:
                if data_func_name != 'lookup':
                    print "%s succeeded when it should not have:\n%s" % (
                        data_func_name,
                        json.dumps(resp, indent=4, sort_keys=True))
                    return False
                elif 'error' not in resp['profile']:
                    print "%s succeeded when it should not have:\n%s" % (
                        data_func_name,
                        json.dumps(resp, indent=4, sort_keys=True))
                    return False

        # this should succeed
        zf_hist = testlib.blockstack_cli_list_zonefile_history("foo.test")
        if len(zf_hist) != 2 * (zi + 1) + 1:
            print "missing zonefile history: %s (expected %s items, got %s)" % (
                zf_hist, zi + 3, len(zf_hist))
            return False

        update_hist = testlib.blockstack_cli_list_update_history("foo.test")
        if len(update_hist) != 2 * (zi + 1) + 1:
            print 'missing zonefile history: %s (expected %s items, got %s)' % (
                zf_hist, zi + 3, len(zf_hist))
            return False

        name_hist = testlib.blockstack_cli_get_name_blockchain_history(
            "foo.test")

        if zf_hist[-1] != nonstandard_zonefile:
            print "invalid zonefile: expected\n%s\ngot\n%s\n" % (
                nonstandard_zonefile, zf_hist[-1])
            return False

        # this should work, but with "non-standard zonefiles"
        hist = testlib.blockstack_cli_list_immutable_data_history(
            "foo.test", "fail")
        if len(hist) != 2 * (zi + 1) + 1:
            print "missing immutable data history: %s (expected %s items, got %s)" % (
                hist, zi + 3, len(hist))
            return False

        if hist[-1] != 'non-standard zonefile':
            print "not a non-standard zonefile: %s" % hist[-1]
            return False

        # verify that we can migrate it back
        resp = testlib.blockstack_cli_migrate("foo.test",
                                              "0123456789abcdef",
                                              force=True,
                                              interactive=False)
        if 'error' in resp:
            print "failed to migrate"
            print json.dumps(resp, indent=4, sort_keys=True)
            return False

        zonefile_hash = resp['zonefile_hash']

        # wait for it to take effect
        for i in xrange(0, 12):
            testlib.next_block(**kw)

        time.sleep(10)

    # see that put_immutable works
    put_result = testlib.blockstack_cli_put_immutable(
        "foo.test",
        "hello_world_immutable",
        json.dumps({'hello': 'world'}),
        password='******')
    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'])

    # 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)

    # see that put_mutable works
    put_result = testlib.blockstack_cli_put_mutable(
        "foo.test",
        "hello_world_mutable",
        json.dumps({'hello': 'world'}),
        password='******')
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True)

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

    global synchronized, value_hash

    import blockstack_integration_tests.atlas_network as atlas_network

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

    testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

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

    # set up RPC daemon
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy( test_proxy )
    wallet_keys = blockstack_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[5].privkey )
    testlib.blockstack_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] )

    # 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 an empty zonefile
    data_pubkey = virtualchain.BitcoinPrivateKey(wallet_keys['data_privkey']).public_key().to_hex()
    empty_zonefile = blockstack_client.user.make_empty_user_zonefile( "foo.test", data_pubkey, urls=["file:///tmp/foo.test"] )
    empty_zonefile_str = json.dumps(empty_zonefile) 
    value_hash = blockstack_client.hash_zonefile( empty_zonefile )

    # propagate the zonefile
    res = testlib.blockstack_cli_update( "foo.test", empty_zonefile_str, "0123456789abcdef" )
    if 'error' in res:
        raise Exception("Failed to update: %s" % res['error'])

    for i in xrange(0, 12):
        testlib.next_block( **kw )
        
    print "Waiting for zonefile propagation"
    time.sleep(10.0)

    # 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
def scenario(wallets, **kw):

    global zonefile_hash

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

    testlib.blockstack_namespace_reveal(
        "test", wallets[1].addr, 52595, 250, 4,
        [6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 10, 10,
        wallets[0].privkey)
    testlib.next_block(**kw)

    testlib.blockstack_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

    wallet = testlib.blockstack_client_initialize_wallet(
        "0123456789abcdef", wallets[2].privkey, wallets[3].privkey,
        wallets[4].privkey)
    resp = testlib.blockstack_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 10 seconds for the backend to submit the register"
    time.sleep(10)

    # wait for the register to get confirmed
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block(**kw)

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

    # wait for initial update to get confirmed
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block(**kw)

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

    # wait for zonefile posting
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block(**kw)

    print >> sys.stderr, "Waiting 10 seconds for the backend to send zonefile"
    time.sleep(10)

    # what's the name's renewal block?
    proxy = testlib.make_proxy()
    res = blockstack_client.get_name_blockchain_record("foo.test", proxy=proxy)
    if 'error' in res:
        print >> sys.stderr, json.dumps(res, indent=4, sort_keys=True)
        return False

    old_expire_block = res['expire_block']

    # send an update, changing the zonefile
    data_pubkey = wallet['data_pubkey']
    zonefile = blockstack_client.zonefile.make_empty_zonefile(
        "foo.test", data_pubkey)
    blockstack_client.user.put_immutable_data_zonefile(
        zonefile,
        "testdata",
        blockstack_client.get_data_hash("testdata"),
        data_url="file:///testdata")
    zonefile_json = json.dumps(zonefile)

    resp = testlib.blockstack_cli_update("foo.test", zonefile_json,
                                         "0123456789abcdef")

    if 'error' in resp:
        print >> sys.stderr, "update error: %s" % resp['error']
        return False

    zonefile_hash = resp['zonefile_hash']

    # wait for it to go through
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block(**kw)

    print >> sys.stderr, "Waiting 10 seconds for the backend to acknowedge the update"
    time.sleep(10)
    # wait for it to go through
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()

        testlib.next_block(**kw)

    # revoke it
    resp = testlib.blockstack_cli_revoke("foo.test", "0123456789abcdef")
    if 'error' in resp:
        print >> sys.stderr, "Revoke request failed:\n%s" % json.dumps(
            resp, indent=4, sort_keys=True)
        return False

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

    # wait for it to go through
    for i in xrange(0, 12):
        testlib.next_block(**kw)
def scenario( wallets, **kw ):

    global synchronized, value_hash

    import blockstack_integration_tests.atlas_network as atlas_network

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

    testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

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

    # set up RPC daemon
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy( test_proxy )
    wallet_keys = blockstack_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[5].privkey )
    testlib.blockstack_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] )

    # start up an Atlas test network with 9 nodes: the main one doing the test, and 8 subordinate ones that treat it as a seed peer
    # organize nodes into a linear chain: node n is neighbor to n-1 and n+1, with the seed at one end.
    # nodes cannot talk to anyone else.
    atlas_nodes = [17000, 17001, 17002, 17003, 17004, 17005, 17006, 17007]
    atlas_topology = {}
    
    atlas_topology[17000] = [16264, 17001]
    atlas_topology[17007] = [17006]

    for i in xrange(1, len(atlas_nodes)-1):
        atlas_topology[atlas_nodes[i]] = [atlas_nodes[i-1], atlas_nodes[i+1]]

    def chain_drop(src_hostport, dest_hostport):
        if src_hostport is None:
            return 0.0

        src_host, src_port = blockstack_client.config.url_to_host_port( src_hostport )
        dest_host, dest_port = blockstack_client.config.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 an empty zonefile
    data_pubkey = virtualchain.BitcoinPrivateKey(wallet_keys['data_privkey']).public_key().to_hex()
    empty_zonefile = blockstack_client.user.make_empty_user_zonefile( "foo.test", data_pubkey, urls=["file:///tmp/foo.test"] )
    empty_zonefile_str = json.dumps(empty_zonefile) 
    value_hash = blockstack_client.hash_zonefile( empty_zonefile )

    # propagate the zonefile
    res = testlib.blockstack_cli_update( "foo.test", empty_zonefile_str, "0123456789abcdef" )

    for i in xrange(0, 12):
        testlib.next_block( **kw )
        
    print "Waiting for zonefile propagation"
    sys.stdout.flush()

    time.sleep(10.0)

    # wait at most 30 seconds for atlas network to converge
    synchronized = False
    for i in xrange(0, 30):
        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 zonefile_hash, final_balance, new_expire_block

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

    testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    wallet = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[2].privkey, wallets[3].privkey, wallets[4].privkey )
    resp = testlib.blockstack_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 10 seconds for the backend to submit the register"
    time.sleep(10)


    # wait for the register to get confirmed 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

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

    # wait for initial update to get confirmed 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

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

    # what's the name's renewal block?
    proxy = testlib.make_proxy()
    res = blockstack_client.get_name_blockchain_record( "foo.test", proxy=proxy )
    if 'error' in res:
        print >> sys.stderr, json.dumps(res, indent=4, sort_keys=True)
        return False
    
    old_expire_block = res['expire_block']

    # send an update, changing the zonefile
    data_pubkey = wallet['data_pubkey']
    zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo.test", data_pubkey )
    blockstack_client.user.put_immutable_data_zonefile( zonefile, "testdata", blockstack_client.get_data_hash("testdata"), data_url="file:///testdata")
    zonefile_json = json.dumps(zonefile)

    resp = testlib.blockstack_cli_update( "foo.test", zonefile_json, "0123456789abcdef" )
    
    if 'error' in resp:
        print >> sys.stderr, "update error: %s" % resp['error']
        return False

    zonefile_hash = resp['zonefile_hash']
    
    # wait for it to go through 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

    print >> sys.stderr, "Waiting 10 seconds for the backend to acknowedge the update"
    time.sleep(10)
    # wait for it to go through 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

    # renew it 
    resp = testlib.blockstack_cli_renew( "foo.test", "0123456789abcdef" )
    if 'error' in resp:
        print >> sys.stderr, "Renewal request failed:\n%s" % json.dumps(resp, indent=4, sort_keys=True)
        return False

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

    # wait for it to go through 
    for i in xrange(0, 6):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

    # verify that it's in the queue
    queue_state = testlib.blockstack_cli_info()
    if 'error' in queue_state:
        print json.dumps(queue_state)
        return False
    
    if not queue_state.has_key('queues'):
        print 'no queues'
        print json.dumps(queue_state)
        return False

    if not queue_state['queues'].has_key('renew'):
        print 'no renew queue'
        print json.dumps(queue_state)
        return False

    if len(queue_state['queues']['renew']) != 1:
        print 'wrong renew state'
        print json.dumps(queue_state)
        return False

    if queue_state['queues']['renew'][0]['name'] != 'foo.test':
        print 'wrong name'
        print json.dumps(queue_state)
        return False

    # wait for it to go through 
    for i in xrange(0, 6):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )


    proxy = testlib.make_proxy()
    res = blockstack_client.get_name_blockchain_record( "foo.test", proxy=proxy )
    if 'error' in res:
        print >> sys.stderr, json.dumps(res, indent=4, sort_keys=True)
        return False


    new_expire_block = res['expire_block']
    if old_expire_block >= new_expire_block + 12:
        # didn't go through
        print >> sys.stderr, "Renewal didn't go through: %s --> %s" % (old_expire_block, new_expire_block)
        return False

    if res['op'] != blockstack_client.config.NAME_REGISTRATION + ":":
        print >> sys.stderr, "Renewal didn't go through (last op is %s)" % res['op']
        error = True
        return False

    final_balance = testlib.getbalance( wallets[2].addr )
def scenario( wallets, **kw ):

    global zonefile_hash

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

    testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    wallet = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[2].privkey, wallets[3].privkey, wallets[5].privkey )
    resp = testlib.blockstack_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 10 seconds for the backend to submit the register"
    time.sleep(10)


    # wait for the register to get confirmed 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

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

    # wait for update to get confirmed 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

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

    # send an update, changing the zonefile
    data_pubkey = wallet['data_pubkey']
    zonefile = blockstack_client.user.make_empty_user_zonefile( "foo.test", data_pubkey )
    blockstack_client.user.put_immutable_data_zonefile( zonefile, "testdata", blockstack_client.get_data_hash("testdata"), data_url="file:///testdata")
    zonefile_json = json.dumps(zonefile)

    resp = testlib.blockstack_cli_update( "foo.test", zonefile_json, "0123456789abcdef" )
    
    if 'error' in resp:
        print >> sys.stderr, "update error: %s" % resp['error']
        return False

    zonefile_hash = resp['value_hash']
    
    # wait for it to go through 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

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

    # transfer to a new address 
    resp = testlib.blockstack_cli_transfer( "foo.test", wallets[4].addr, "0123456789abcdef" )

    if 'error' in resp:
        print >> sys.stderr, "transfer error: %s" % resp['error']
        return False

    # wait for it to go through 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

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

    # regenerate the wallet, with the new owner address
    wallet = testlib.blockstack_client_set_wallet( "0123456789abcdef", wallets[5].privkey, wallets[4].privkey, wallets[5].privkey )

    # send another update, changing the zonefile again
    # pay for it using the same payment address
    zonefile = blockstack_client.user.make_empty_user_zonefile( "foo.test", new_data_pubkey )
    blockstack_client.user.put_immutable_data_zonefile( zonefile, "testdata", blockstack_client.get_data_hash("testdata"), data_url="file:///testdata")
    zonefile_json = json.dumps(zonefile)

    resp = testlib.blockstack_cli_update( "foo.test", zonefile_json, "0123456789abcdef" )
    
    if 'error' in resp:
        print >> sys.stderr, "update error: %s" % resp['error']
        return False

    zonefile_hash = resp['value_hash']
    
    # wait for it to go through 
    for i in xrange(0, 12):
        # warn the serialization checker that this changes behavior from 0.13
        print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
        sys.stdout.flush()
        
        testlib.next_block( **kw )

    print >> sys.stderr, "Waiting 10 seconds for the backend to acknowedge the update"
    time.sleep(10)
def scenario( wallets, **kw ):

    global put_result, wallet_keys, legacy_profile, zonefile_hash, zonefile_hash_2, error


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

    testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

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

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

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

    result_1 = testlib.blockstack_name_update( "foo.test", legacy_hash, wallets[3].privkey )
    testlib.next_block( **kw )

    rc = blockstack_client.storage.put_immutable_data( None, result_1['transaction_hash'], data_hash=legacy_hash, data_text=legacy_txt )
    assert rc is not None

    testlib.next_block( **kw )

    # migrate profiles to standard zonefiles
    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 

    testlib.next_block( **kw )

    # give foo.test a nonstandard zonefile (as something that serializes to JSON)
    nonstandard_zonefile_json = {'nonstandard': 'true', 'error': 'nonstandard'}
    nonstandard_zonefile_txt = json.dumps(nonstandard_zonefile_json, sort_keys=True)
    nonstandard_zonefile_raw = binascii.unhexlify( "".join(["%02x" % i for i in xrange(0, 256)]))

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

    zf_data = [nonstandard_zonefile_txt, nonstandard_zonefile_raw]
    for zi in xrange(0, len(zf_data)):
        nonstandard_zonefile = zf_data[zi]

        resp = testlib.blockstack_cli_update( "foo.test", nonstandard_zonefile, "0123456789abcdef", nonstandard=True )
        if 'error' in resp:
            print "failed to put nonstandard zonefile '%s'" % nonstandard_zonefile
            print json.dumps(resp, indent=4, sort_keys=True)
            error = True
            return

        testlib.expect_atlas_zonefile(resp['value_hash'])

        # wait for it to take effect
        for i in xrange(0, 12):
            testlib.next_block( **kw )

        time.sleep(3)

        # getting zonefile should still work...
        resp = testlib.blockstack_cli_advanced_get_name_zonefile( "foo.test", json=True )
        if 'error' in resp:
            print "failed to get zonefile %s" % zi
            print json.dumps(resp, indent=4, sort_keys=True)
            error = True
            return 

        if 'warning' not in resp:
            print "no non-standard warning:\n%s" % json.dumps(resp, indent=4, sort_keys=True)
            error = True
            return

        if resp['zonefile'] != nonstandard_zonefile:
            print "failed to load nonstandard zonefile json"
            print "expected:\n%s\n\ngot:\n%s" % (nonstandard_zonefile, resp['zonefile'])
            error = True
            return 

        # the following should all fail
        dataplane_funcs = [
            ("lookup",        lambda: testlib.blockstack_cli_lookup( "foo.test" )),
            ("put_immutable", lambda: testlib.blockstack_cli_advanced_put_immutable( "foo.test", "fail", '{"Fail": "Yes"}' )),
            ("get_immutable", lambda: testlib.blockstack_cli_advanced_get_immutable( "foo.test", "fail" )),
            ("put_mutable",   lambda: testlib.blockstack_cli_advanced_put_mutable( "foo.test", "fail", '{"fail": "yes"}' )),
            ("get_mutable",   lambda: testlib.blockstack_cli_advanced_get_mutable( "foo.test", "fail" )),
            ("delete_immutable", lambda: testlib.blockstack_cli_advanced_delete_immutable( "foo.test", "00" * 32 )),
            ("delete_mutable", lambda: testlib.blockstack_cli_advanced_delete_mutable( "foo.test", "fail" ))
        ]

        for data_func_name, data_func in dataplane_funcs:
            resp = data_func()
            if 'error' not in resp:
                print "%s succeeded when it should not have:\n%s" % (data_func_name, json.dumps(resp, indent=4, sort_keys=True))
                error = True
                return
      
        # this should succeed
        zf_hist = testlib.blockstack_cli_advanced_list_zonefile_history( "foo.test" )
        if len(zf_hist) != 2*(zi+1)+1:
            print "missing zonefile history: %s (expected %s items, got %s)" % (zf_hist, zi+3, len(zf_hist))
            error = True
            return

        if zf_hist[-1] != nonstandard_zonefile:
            print "invalid zonefile: expected\n%s\ngot\n%s\n" % (nonstandard_zonefile, zf_hist[-1])
            error = True
            return

        # this should work, but with "non-standard zonefiles"
        hist = testlib.blockstack_cli_advanced_list_immutable_data_history("foo.test", "fail")
        if len(hist) != 2*(zi+1)+1:
            print "missing immutable data history: %s (expected %s items, got %s)" % (hist, zi+3, len(hist))
            error = True
            return 

        if hist[-1] != 'non-standard zonefile':
            print "not a non-standard zonefile: %s" % hist[-1]
            error = True
            return 

        # verify that we can migrate it back
        resp = testlib.blockstack_cli_migrate( "foo.test", "0123456789abcdef", force=True )
        if 'error' in resp:
            print "failed to migrate"
            print json.dumps(resp, indent=4, sort_keys=True)
            error = True
            return 

        zonefile_hash = resp['zonefile_hash']

        # wait for it to take effect
        for i in xrange(0, 12):
            testlib.next_block( **kw )

        time.sleep(3)

    # see that put_immutable works
    put_result = blockstack_client.put_immutable( "foo.test", "hello_world_immutable", {"hello": "world"}, 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'])

    # 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(3)

    # see that put_mutable works
    put_result = blockstack_client.put_mutable( "foo.test", "hello_world_mutable", {"hello": "world"}, proxy=test_proxy, wallet_keys=wallet_keys_2 )
    if 'error' in put_result:
        print json.dumps(put_result, indent=4, sort_keys=True )
    
    testlib.next_block( **kw )
def scenario( wallets, **kw ):

    global synchronized, value_hash

    import blockstack_integration_tests.atlas_network as atlas_network

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

    testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

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

    # set up RPC daemon
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy( test_proxy )
    wallet_keys = blockstack_client.make_wallet_keys( owner_privkey=wallets[3].privkey, data_privkey=wallets[4].privkey, payment_privkey=wallets[5].privkey )
    testlib.blockstack_client_set_wallet( "0123456789abcdef", wallet_keys['payment_privkey'], wallet_keys['owner_privkey'], wallet_keys['data_privkey'] )

    # start up an Atlas test network with 9 nodes: the main one doing the test, and 8 subordinate ones that treat it as a seed peer
    # only the seed node will be publicly routable; the other 8 will be unable to directly talk to each other.
    atlas_nodes = [17000, 17001, 17002, 17003, 17004, 17005, 17006, 17007]
    atlas_topology = {}
    for node_port in atlas_nodes:
        atlas_topology[node_port] = [16264]

    def nat_drop(src_hostport, dest_hostport):
        if dest_hostport is None:
            return 0.0
        
        host, port = blockstack_client.config.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 25 seconds for the altas peers to catch up"
    time.sleep(25.0)

    # make an empty zonefile
    data_pubkey = virtualchain.BitcoinPrivateKey(wallet_keys['data_privkey']).public_key().to_hex()
    empty_zonefile = blockstack_client.user.make_empty_user_zonefile( "foo.test", data_pubkey, urls=["file:///tmp/foo.test"] )
    empty_zonefile_str = json.dumps(empty_zonefile) 
    value_hash = blockstack_client.hash_zonefile( empty_zonefile )

    # propagate the zonefile
    res = testlib.blockstack_cli_update( "foo.test", empty_zonefile_str, "0123456789abcdef" )

    for i in xrange(0, 12):
        testlib.next_block( **kw )
        
    print "Waiting for zonefile propagation"
    time.sleep(10.0)

    # 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