Example #1
0
def check( state_engine ):

    global wallet_keys, datasets, zonefile_hash

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    # not preordered
    preorder = state_engine.get_name_preorder( "foo.test", pybitcoin.make_pay_to_address_script(wallets[2].addr), wallets[3].addr )
    if preorder is not None:
        print "still have preorder"
        return False
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "name does not exist"
        return False 

    # owned 
    if name_rec['address'] != wallets[3].addr or name_rec['sender'] != pybitcoin.make_pay_to_address_script(wallets[3].addr):
        print "name has wrong owner"
        return False 

    # have right hash 
    if name_rec['value_hash'] != zonefile_hash:
        print "Invalid zonefile hash"
        return False 

    # have no data
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy( test_proxy )

    for i in xrange(0, len(datasets)):
        print "get hello_world_%s" % (i+1)
        dat = testlib.blockstack_cli_get_mutable( "foo.test", "hello_world_%s" % (i+1) )
        if dat is not None and 'error' not in dat:
            print "still have '%s'\n%s" % ("hello_world_%s" % (i+1), json.dumps(dat,indent=4,sort_keys=True))
            return False

        if 'error' in dat and dat['error'] != 'Failed to fetch mutable data':
            print json.dumps(dat, indent=4, sort_keys=True)
            return False

    return True
def check( state_engine ):

    global error

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    # not preordered
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(wallets[2].addr), wallets[3].addr )
    if preorder is not None:
        print "still have preorder"
        return False
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "name does not exist"
        return False 

    # owned 
    if name_rec['address'] != wallets[3].addr or name_rec['sender'] != virtualchain.make_payment_script(wallets[3].addr):
        print "name has wrong owner"
        return False 

    # have right data 
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy( test_proxy )

    # should always work
    for i in xrange(1, len(datasets)):
        immutable_data = testlib.blockstack_cli_get_immutable('foo.test', 'hello_world_{}_immutable'.format(i+1))
        if immutable_data is None:
            print "No data received for immutable dataset %s" % i
            return False 

        if 'error' in immutable_data:
            print "No data received for immutable dataset %s: %s" % (i, immutable_data['error'])
            return False

        if not immutable_data.has_key('data'):
            print "Missing data\n%s" % json.dumps(immutable_data, indent=4, sort_keys=True)
            return False 

        data_json = json.loads(immutable_data['data'])
        if data_json != datasets[i]:
            print "did not get dataset %s\ngot %s\nexpected %s" % (i, data_json, datasets[i])
            return False 

        mutable_data = testlib.blockstack_cli_get_mutable('foo.test', 'hello_world_{}_mutable'.format(i+1))
        if mutable_data is None:
            print "No data received for mutable dataset %s" % (i+1)
            return False

        if 'error' in mutable_data:
            print "No data received for mutable dataset %s: %s" % (i+1, mutable_data['error'])
            return False

        data_json = json.loads(mutable_data['data'])
        if data_json != datasets[i]:
            print "did not get dataset %s\ngot %s\nexpected %s" % (i+1, data_json, datasets[i])
            return False

    # should fail 
    immutable_data = testlib.blockstack_cli_get_immutable('foo.test', 'hello_world_1_immutable')
    if immutable_data is not None and 'error' not in immutable_data:
        print "Got deleted immutable dataset"
        return False

    mutable_data = testlib.blockstack_cli_get_mutable( "foo.test", "hello_world_1_mutable")
    if mutable_data is not None and 'error' not in mutable_data:
        print "Got deleted mutable dataset"
        return False

    return True
Example #3
0
def check( state_engine ):

    global wallet_keys, wallet_keys_2, datasets, zonefile_hash, zonefile_hash_2


    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    # not preordered
    names = ['foo.test', 'bar.test']
    wallet_keys_list = [wallet_keys, wallet_keys_2]
    zonefile_hashes = [zonefile_hash[:], zonefile_hash_2[:]]

    for i in xrange(0, len(names)):
        name = names[i]
        wallet_payer = 3 * (i+1) - 1
        wallet_owner = 3 * (i+1)
        wallet_data_pubkey = 3 * (i+1) + 1
        wallet_keys = wallet_keys_list[i]
        zonefile_hash = zonefile_hashes[i]

        preorder = state_engine.get_name_preorder( name, pybitcoin.make_pay_to_address_script(wallets[wallet_payer].addr), wallets[wallet_owner].addr )
        if preorder is not None:
            print "still have preorder"
            return False
    
        # registered 
        name_rec = state_engine.get_name( name )
        if name_rec is None:
            print "name does not exist"
            return False 

        # owned 
        if name_rec['address'] != wallets[wallet_owner].addr or name_rec['sender'] != pybitcoin.make_pay_to_address_script(wallets[wallet_owner].addr):
            print "name has wrong owner"
            return False 

        # zonefile is NOT legacy 
        user_zonefile = blockstack_client.zonefile.load_name_zonefile( name, zonefile_hash )
        if 'error' in user_zonefile:
            print json.dumps(user_zonefile, indent=4, sort_keys=True)
            return False 

        if blockstack_profiles.is_profile_in_legacy_format( user_zonefile ):
            print "legacy still"
            print json.dumps(user_zonefile, indent=4, sort_keys=True)
            return False

        # still have all the right info 
        user_profile = blockstack_client.profile.get_profile( name, user_zonefile=user_zonefile )
        if user_profile is None or 'error' in user_profile:
            if user_profile is not None:
                print json.dumps(user_profile, indent=4, sort_keys=True)
            else:
                print "\n\nprofile is None\n\n"
                        
            return False

    # can get mutable data 
    res = testlib.blockstack_cli_get_mutable( "bar.test", "hello_world_mutable" )
    print 'mutable: {}'.format(res)

    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        return False
    
    if json.loads(res['data']) != {'hello': 'world'}:
        print 'invalid data: {}'.format(res['data'])
        return False

    # can get immutable data by name
    res = testlib.blockstack_cli_get_immutable( 'foo.test', 'hello_world_immutable' )
    print 'immutable by name: {}'.format(res)

    if 'error' in res:
        return res

    if json.loads(res['data']) != {'hello': 'world_immutable'}:
        print 'invalid immutable data: {}'.format(res['data'])
        return False

    # can get immutable data by hash
    hsh = res['hash']
    res = testlib.blockstack_cli_get_immutable( 'foo.test', hsh )
    print 'immutable: {}'.format(res)

    if 'error' in res:
        return res

    if json.loads(res['data']) != {'hello': 'world_immutable'}:
        print 'invalid immutable data by hash: {}'.format(res['data'])
        return False

    return True
Example #4
0
def check(state_engine):

    global wallet_keys, datasets, zonefile_hash

    if error:
        return False

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        print "namespace not ready"
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        print "no namespace"
        return False

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False

    name = "foo.test"
    wallet_payer = 2
    wallet_owner = 3
    wallet_data_pubkey = 4

    # not preordered
    preorder = state_engine.get_name_preorder(
        name, virtualchain.make_payment_script(wallets[wallet_payer].addr),
        wallets[wallet_owner].addr)
    if preorder is not None:
        print "still have preorder"
        return False

    # registered
    name_rec = state_engine.get_name(name)
    if name_rec is None:
        print "name does not exist"
        return False

    # owned
    if name_rec['address'] != wallets[wallet_owner].addr or name_rec[
            'sender'] != virtualchain.make_payment_script(
                wallets[wallet_owner].addr):
        print "name has wrong owner"
        return False

    # zonefile is NOT legacy
    user_zonefile = blockstack_client.zonefile.load_name_zonefile(
        name, zonefile_hash)
    if 'error' in user_zonefile:
        print json.dumps(user_zonefile, indent=4, sort_keys=True)
        return False

    if blockstack_profiles.is_profile_in_legacy_format(user_zonefile):
        print "legacy still"
        print json.dumps(user_zonefile, indent=4, sort_keys=True)
        return False

    # still have a profile with data
    user_profile = blockstack_client.profile.get_profile(
        name, user_zonefile=user_zonefile)
    if user_profile is None or 'error' in user_profile:
        if user_profile is not None:
            print json.dumps(user_profile, indent=4, sort_keys=True)
        else:
            print "\n\nprofile is None\n\n"

        return False

    # still have immutable data
    immutable_data_by_name = testlib.get_immutable_by_name(
        'foo.test', 'hello_world_immutable')
    if immutable_data_by_name is None:
        print "No data received by name for dataset %s" % i
        return False

    if 'error' in immutable_data_by_name:
        print "No data received for dataset hello_world_immutable"
        return False

    if not immutable_data_by_name.has_key('data'):
        print "Misisng data\n%s" % json.dumps(
            immutable_data_by_name, indent=4, sort_keys=True)
        return False

    data_json = json.loads(immutable_data_by_name['data'])
    if data_json != {'hello': 'world'}:
        print "did not get dataset hello_world_immutable\ngot %s\nexpected %s" % (
            data_json, {
                'hello': 'world'
            })
        return False

    # still have mutable data
    dat = testlib.blockstack_cli_get_mutable('foo.test', 'hello_world_mutable')
    if dat is None:
        print "No hello_world_mutable"
        return False

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

    if json.loads(dat['data']) != {'hello': 'world'}:
        print "did not get mutable dataset"
        return False

    return True
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)
Example #6
0
def check(state_engine):

    global wallet_keys, datasets, zonefile_hash

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        print "namespace not ready"
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        print "no namespace"
        return False

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False

    # not preordered
    preorder = state_engine.get_name_preorder(
        "foo.test", pybitcoin.make_pay_to_address_script(wallets[2].addr),
        wallets[3].addr)
    if preorder is not None:
        print "still have preorder"
        return False

    # registered
    name_rec = state_engine.get_name("foo.test")
    if name_rec is None:
        print "name does not exist"
        return False

    # owned
    if name_rec['address'] != wallets[3].addr or name_rec[
            'sender'] != pybitcoin.make_pay_to_address_script(wallets[3].addr):
        print "name has wrong owner"
        return False

    # have right hash
    if name_rec['value_hash'] != zonefile_hash:
        print "Invalid zonefile hash"
        return False

    # have right data
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy(test_proxy)

    for i in xrange(0, len(datasets)):
        print "get hello_world_%s" % (i + 1)
        dat = testlib.blockstack_cli_get_mutable(
            "foo.test", "hello_world_{}".format(i + 1))
        if dat is None:
            print "No data '%s'" % ("hello_world_%s" % (i + 1))
            return False

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

        if json.loads(dat['data']) != datasets[i]:
            print "Mismatch %s: %s != %s" % (i, dat, datasets[i])
            return False

    res = testlib.blockstack_cli_lookup("foo.test")
    if 'error' in res:
        print 'error looking up profile: {}'.format(res)
        return False

    assert 'profile' in res
    assert 'zonefile' in res

    return True
def check( state_engine ):

    global wallet_keys, datasets, zonefile_hash

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    # not preordered
    preorder = state_engine.get_name_preorder( "foo.test", pybitcoin.make_pay_to_address_script(wallets[2].addr), wallets[3].addr )
    if preorder is not None:
        print "still have preorder"
        return False
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "name does not exist"
        return False 

    # owned 
    if name_rec['address'] != wallets[3].addr or name_rec['sender'] != pybitcoin.make_pay_to_address_script(wallets[3].addr):
        print "name has wrong owner"
        return False 

    # have right hash 
    if name_rec['value_hash'] != zonefile_hash:
        print "Invalid zonefile hash"
        return False 

    # zonefile is NOT legacy 
    user_zonefile = blockstack_client.zonefile.load_name_zonefile( 'foo.test', zonefile_hash )
    if 'error' in user_zonefile:
        print json.dumps(user_zonefile, indent=4, sort_keys=True)
        return False 

    if blockstack_profiles.is_profile_in_legacy_format( user_zonefile ):
        print "legacy still"
        print json.dumps(user_zonefile, indent=4, sort_keys=True)
        return False

    # zonefile has no key 
    zonefile_key = blockstack_client.user.user_zonefile_data_pubkey(user_zonefile)
    if zonefile_key is not None:
        print 'still have zonefile key'
        print json.dumps(user_zonefile, indent=4, sort_keys=True)
        return False

    # have right data 
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy( test_proxy )

    for i in xrange(0, len(datasets)):
        print "get hello_world_%s" % (i+1)
        dat = testlib.blockstack_cli_get_mutable( "foo.test", "hello_world_{}".format(i+1), public_key=wallets[4].pubkey_hex )
        if dat is None:
            print "No data '%s'" % ("hello_world_%s" % (i+1))
            return False

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

        if json.loads(dat['data']) != datasets[i]:
            print "Mismatch %s: %s != %s" % (i, dat, datasets[i])
            return False
    
    res = testlib.blockstack_cli_lookup("foo.test")
    if 'error' in res:
        print 'error looking up profile: {}'.format(res)
        return False

    assert 'profile' in res
    assert 'zonefile' in res

    return True
Example #8
0
        profile = blockstack_client.storage.parse_mutable_data(
            raw_profile, user_pubkey)

    except Exception, e:
        traceback.print_exc()
        print "Invalid profile"
        return False

    # have right data
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy(test_proxy)

    for i in xrange(0, len(datasets)):
        print "get hello_world_%s" % (i + 1)
        dat = testlib.blockstack_cli_get_mutable(
            'foo.test',
            "hello_world_%s" % (i + 1),
            public_key=wallets[4].pubkey_hex)
        if dat is None:
            print "No data '%s'" % ("hello_world_%s" % (i + 1))
            return False

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

        if json.loads(dat['data']) != datasets[i]:
            print "Mismatch %s: %s %s != %s %s" % (
                i, dat['data'], type(
                    dat['data']), datasets[i], type(datasets[i]))
            return False
        # profile will be in 'raw' form
        raw_profile = profile_resp['profile']
        profile = blockstack_client.storage.parse_mutable_data( raw_profile, user_pubkey )

    except Exception, e:
        traceback.print_exc()
        print "Invalid profile"
        return False

    # have right data 
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy( test_proxy )

    for i in xrange(0, len(datasets)):
        print "get hello_world_%s" % (i+1)
        dat = testlib.blockstack_cli_get_mutable( 'foo.test', "hello_world_%s" % (i+1), public_key=wallets[4].pubkey_hex )
        if dat is None:
            print "No data '%s'" % ("hello_world_%s" % (i+1))
            return False

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

        if json.loads(dat['data']) != datasets[i]:
            print "Mismatch %s: %s %s != %s %s" % (i, dat['data'], type(dat['data']), datasets[i], type(datasets[i]))
            return False
    
    res = blockstack_client.get_profile('foo.test')
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
def check( state_engine ):

    global wallet_keys, wallet_keys_2, datasets, zonefile_hash, zonefile_hash_2


    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    # not preordered
    names = ['foo.test', 'bar.test']
    wallet_keys_list = [wallet_keys, wallet_keys_2]
    zonefile_hashes = [zonefile_hash[:], zonefile_hash_2[:]]

    for i in xrange(0, len(names)):
        name = names[i]
        wallet_payer = 3 * (i+1) - 1
        wallet_owner = 3 * (i+1)
        wallet_data_pubkey = 3 * (i+1)  # same as owner key
        wallet_keys = wallet_keys_list[i]
        zonefile_hash = zonefile_hashes[i]

        preorder = state_engine.get_name_preorder( name, pybitcoin.make_pay_to_address_script(wallets[wallet_payer].addr), wallets[wallet_owner].addr )
        if preorder is not None:
            print "still have preorder"
            return False
    
        # registered 
        name_rec = state_engine.get_name( name )
        if name_rec is None:
            print "name does not exist"
            return False 

        # owned 
        if name_rec['address'] != wallets[wallet_owner].addr or name_rec['sender'] != pybitcoin.make_pay_to_address_script(wallets[wallet_owner].addr):
            print "name has wrong owner"
            return False 

        # zonefile is NOT legacy 
        user_zonefile = blockstack_client.zonefile.load_name_zonefile( name, zonefile_hash )
        if 'error' in user_zonefile:
            print json.dumps(user_zonefile, indent=4, sort_keys=True)
            return False 

        if blockstack_profiles.is_profile_in_legacy_format( user_zonefile ):
            print "legacy still"
            print json.dumps(user_zonefile, indent=4, sort_keys=True)
            return False

        # still have all the right info 
        user_profile = blockstack_client.profile.get_profile( name, user_zonefile=user_zonefile )
        if user_profile is None or 'error' in user_profile:
            if user_profile is not None:
                print json.dumps(user_profile, indent=4, sort_keys=True)
            else:
                print "\n\nprofile is None\n\n"

            return False

    # can get mutable data 
    res = testlib.blockstack_cli_get_mutable( "bar.test", "hello_world_mutable" )
    print 'mutable: {}'.format(res)

    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        return False
    
    if json.loads(res['data']) != {'hello': 'world'}:
        print 'invalid data: {}'.format(res['data'])
        return False

    # can get immutable data by name
    res = testlib.blockstack_cli_get_immutable( 'foo.test', 'hello_world_immutable' )
    print 'immutable by name: {}'.format(res)

    if 'error' in res:
        return res

    if json.loads(res['data']) != {'hello': 'world_immutable'}:
        print 'invalid immutable data: {}'.format(res['data'])
        return False

    # can get immutable data by hash
    hsh = res['hash']
    res = testlib.blockstack_cli_get_immutable( 'foo.test', hsh )
    print 'immutable: {}'.format(res)

    if 'error' in res:
        return res

    if json.loads(res['data']) != {'hello': 'world_immutable'}:
        print 'invalid immutable data by hash: {}'.format(res['data'])
        return False

    return True
def check( state_engine ):

    global error

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    # not preordered
    preorder = state_engine.get_name_preorder( "foo.test", pybitcoin.make_pay_to_address_script(wallets[2].addr), wallets[3].addr )
    if preorder is not None:
        print "still have preorder"
        return False
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "name does not exist"
        return False 

    # owned 
    if name_rec['address'] != wallets[3].addr or name_rec['sender'] != pybitcoin.make_pay_to_address_script(wallets[3].addr):
        print "name has wrong owner"
        return False 

    # have right data 
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy( test_proxy )

    # should always work
    for i in xrange(1, len(datasets)):
        immutable_data = testlib.blockstack_cli_get_immutable('foo.test', 'hello_world_{}_immutable'.format(i+1))
        if immutable_data is None:
            print "No data received for immutable dataset %s" % i
            return False 

        if 'error' in immutable_data:
            print "No data received for immutable dataset %s: %s" % (i, immutable_data['error'])
            return False

        if not immutable_data.has_key('data'):
            print "Missing data\n%s" % json.dumps(immutable_data, indent=4, sort_keys=True)
            return False 

        data_json = json.loads(immutable_data['data'])
        if data_json != datasets[i]:
            print "did not get dataset %s\ngot %s\nexpected %s" % (i, data_json, datasets[i])
            return False 

        mutable_data = testlib.blockstack_cli_get_mutable('foo.test', 'hello_world_{}_mutable'.format(i+1))
        if mutable_data is None:
            print "No data received for mutable dataset %s" % (i+1)
            return False

        if 'error' in mutable_data:
            print "No data received for mutable dataset %s: %s" % (i+1, mutable_data['error'])
            return False

        data_json = json.loads(mutable_data['data'])
        if data_json != datasets[i]:
            print "did not get dataset %s\ngot %s\nexpected %s" % (i+1, data_json, datasets[i])
            return False

    # should fail 
    immutable_data = testlib.blockstack_cli_get_immutable('foo.test', 'hello_world_1_immutable')
    if immutable_data is not None and 'error' not in immutable_data:
        print "Got deleted immutable dataset"
        return False

    mutable_data = testlib.blockstack_cli_get_mutable( "foo.test", "hello_world_1_mutable")
    if mutable_data is not None and 'error' not in mutable_data:
        print "Got deleted mutable dataset"
        return False

    return True
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 = pybitcoin.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(3)

        # getting zonefile should still work...
        resp = testlib.blockstack_cli_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)
            return False 

        if 'warning' not in resp:
            print "no non-standard warning:\n%s" % 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:
                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 )
        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(3)

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

    # 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 check( state_engine ):

    global wallet_keys, datasets, zonefile_hash

    if error:
        return False

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    name = "foo.test"
    wallet_payer = 2
    wallet_owner = 3
    wallet_data_pubkey = 4

    # not preordered
    preorder = state_engine.get_name_preorder( name, pybitcoin.make_pay_to_address_script(wallets[wallet_payer].addr), wallets[wallet_owner].addr )
    if preorder is not None:
        print "still have preorder"
        return False

    # registered 
    name_rec = state_engine.get_name( name )
    if name_rec is None:
        print "name does not exist"
        return False 

    # owned 
    if name_rec['address'] != wallets[wallet_owner].addr or name_rec['sender'] != pybitcoin.make_pay_to_address_script(wallets[wallet_owner].addr):
        print "name has wrong owner"
        return False 

    # zonefile is NOT legacy 
    user_zonefile = blockstack_client.zonefile.load_name_zonefile( name, zonefile_hash )
    if 'error' in user_zonefile:
        print json.dumps(user_zonefile, indent=4, sort_keys=True)
        return False 

    if blockstack_profiles.is_profile_in_legacy_format( user_zonefile ):
        print "legacy still"
        print json.dumps(user_zonefile, indent=4, sort_keys=True)
        return False

    # still have a profile with data
    user_profile = blockstack_client.profile.get_profile( name, user_zonefile=user_zonefile )
    if user_profile is None or 'error' in user_profile:
        if user_profile is not None:
            print json.dumps(user_profile, indent=4, sort_keys=True)
        else:
            print "\n\nprofile is None\n\n"
                    
        return False

    # still have immutable data
    immutable_data_by_name = testlib.get_immutable_by_name('foo.test', 'hello_world_immutable')
    if immutable_data_by_name is None:
        print "No data received by name for dataset %s" % i
        return False 

    if 'error' in immutable_data_by_name:
        print "No data received for dataset hello_world_immutable"
        return False 

    if not immutable_data_by_name.has_key('data'):
        print "Misisng data\n%s" % json.dumps(immutable_data_by_name, indent=4, sort_keys=True)
        return False 

    data_json = json.loads(immutable_data_by_name['data'])
    if data_json != {'hello': 'world'}:
        print "did not get dataset hello_world_immutable\ngot %s\nexpected %s" % (data_json, {'hello': 'world'})
        return False 

    # still have mutable data
    dat = testlib.blockstack_cli_get_mutable( 'foo.test', 'hello_world_mutable' )
    if dat is None:
        print "No hello_world_mutable"
        return False 

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

    if json.loads(dat['data']) != {'hello': 'world'}:
        print "did not get mutable dataset"
        return False

    return True