def add_subdomains(subdomains, domain_fqa, zonefile_json, filter_function = None):
    if filter_function is None:
        filter_function = (lambda subdomain, domain: True)

    zf = copy.deepcopy(zonefile_json)
    if "txt" in zf:
        zf["txt"] = list([ x for x in zf["txt"]
                           if not is_subdomain_record(x)])

    if len(set(subdomains)) != len(subdomains):
        raise Exception("Same subdomain listed multiple times")

    subdomains_failed = []
    for ix, subdomain in enumerate(subdomains):
        # step 1: see if this resolves to an already defined subdomain
        filter_passed = filter_function(subdomain.subdomain_name, domain_fqa)
        if not filter_passed:
            subdomains_failed.append(ix)
        else:
            # step 2: create the subdomain record, adding it to zf
            try:
                _extend_with_subdomain(zf, subdomain)
            except Exception as e:
                subdomains_failed.append(ix)

    zf_txt = blockstack_zones.make_zone_file(zf)
    return zf_txt, subdomains_failed
示例#2
0
def serialize_zonefile( zonefile_data ):
    """
    Serialize a zonefile to string
    """
    
    zonefile_txt = blockstack_zones.make_zone_file( zonefile_data )
    return zonefile_txt
示例#3
0
def add_subdomains(subdomains,
                   domain_fqa,
                   zonefile_json,
                   filter_function=None):
    if filter_function is None:
        filter_function = (lambda subdomain, domain: True)

    zf = copy.deepcopy(zonefile_json)
    if "txt" in zf:
        zf["txt"] = list([x for x in zf["txt"] if not is_subdomain_record(x)])

    if len(set(subdomains)) != len(subdomains):
        raise Exception("Same subdomain listed multiple times")

    subdomains_failed = []
    for ix, subdomain in enumerate(subdomains):
        # step 1: see if this resolves to an already defined subdomain
        filter_passed = filter_function(subdomain.subdomain_name, domain_fqa)
        if not filter_passed:
            subdomains_failed.append(ix)
        else:
            # step 2: create the subdomain record, adding it to zf
            try:
                _extend_with_subdomain(zf, subdomain)
            except Exception as e:
                subdomains_failed.append(ix)

    zf_txt = blockstack_zones.make_zone_file(zf)
    return zf_txt, subdomains_failed
示例#4
0
def store_name_zonefile(name, user_zonefile, txid, storage_drivers=None):
    """
    Store JSON user zonefile data to the immutable storage providers, synchronously.
    This is only necessary if we've added/changed/removed immutable data.

    Return (True, hash(user zonefile)) on success
    Return (False, None) on failure
    """

    storage_drivers = [] if storage_drivers is None else storage_drivers

    assert not blockstack_profiles.is_profile_in_legacy_format(
        user_zonefile), 'User zonefile is a legacy profile'
    assert user_db.is_user_zonefile(
        user_zonefile), 'Not a user zonefile (maybe a custom legacy profile?)'

    # serialize and send off
    user_zonefile_txt = blockstack_zones.make_zone_file(user_zonefile,
                                                        origin=name,
                                                        ttl=USER_ZONEFILE_TTL)

    return store_name_zonefile_data(name,
                                    user_zonefile_txt,
                                    txid,
                                    storage_drivers=storage_drivers)
示例#5
0
def store_zonefile_to_storage(zonefile_dict, required=[]):
    """
    Upload a zonefile to our storage providers.
    Return True if at least one provider got it.
    Return False otherwise.
    """
    zonefile_hash = hash_zonefile(zonefile_dict)
    name = zonefile_dict['$origin']
    zonefile_text = blockstack_zones.make_zone_file(zonefile_dict)

    # find the tx that paid for this zonefile
    txid = get_zonefile_txid(zonefile_dict)
    if txid is None:
        log.error("No txid for zonefile hash '%s' (for '%s')" %
                  (zonefile_hash, name))
        return False

    rc = blockstack_client.storage.put_immutable_data(None,
                                                      txid,
                                                      data_hash=zonefile_hash,
                                                      data_text=zonefile_text,
                                                      required=required)
    if not rc:
        log.error("Failed to store zonefile '%s' (%s) for '%s'" %
                  (zonefile_hash, txid, name))
        return False

    return True
示例#6
0
    def test_zone_file_creation_txt(self):
        json_zone_file = zone_file_objects["sample_txt_1"]
        zone_file = make_zone_file(json_zone_file)
        print zone_file
        self.assertTrue(isinstance(zone_file, (unicode, str)))
        self.assertTrue("$ORIGIN" in zone_file)
        self.assertTrue("$TTL" in zone_file)
        self.assertTrue("@ IN SOA" in zone_file)

        zone_file = parse_zone_file(zone_file)
        self.assertTrue(isinstance(zone_file, dict))
        self.assertTrue("soa" in zone_file)
        self.assertTrue("mx" in zone_file)
        self.assertTrue("ns" in zone_file)
        self.assertTrue("a" in zone_file)
        self.assertTrue("cname" in zone_file)
        self.assertTrue("$ttl" in zone_file)
        self.assertTrue("$origin" in zone_file)
        self.assertTrue("txt" in zone_file)
        self.assertEqual(zone_file["txt"][0]["name"], "single")
        self.assertEqual(zone_file["txt"][0]["txt"], "everything I do")
        self.assertEqual(zone_file["txt"][1]["name"], "singleTTL")
        self.assertEqual(zone_file["txt"][1]["ttl"], 100)
        self.assertEqual(zone_file["txt"][1]["txt"], "everything I do")
        self.assertEqual(zone_file["txt"][2]["name"], "multi")
        self.assertEqual(zone_file["txt"][2]["txt"], 
                         ["everything I do", "I do for you"])
        self.assertEqual(zone_file["txt"][3]["name"], "multiTTL")
        self.assertEqual(zone_file["txt"][3]["ttl"], 100)
        self.assertEqual(zone_file["txt"][3]["txt"], 
                         ["everything I do", "I do for you"])        
    def test_sigs(self):
        fake_privkey_hex = "5512612ed6ef10ea8c5f9839c63f62107c73db7306b98588a46d0cd2c3d15ea5"
        sk = keylib.ECPrivateKey(fake_privkey_hex)
        pk = sk.public_key()

        for t in ["foo", "bar", "bassoon"]:
            self.assertTrue(subdomains.verify(pk.address(), t,
                                              subdomains.sign(sk, t)), t)

        subdomain = subdomains.Subdomain("bar.id", "foo", subdomains.encode_pubkey_entry(sk), 3, "")

        user_zf = {
            '$origin': 'foo',
            '$ttl': 3600,
            'txt' : [], 'uri' : []
        }

        user_zf['uri'].append(zonefile.url_to_uri_record("https://foo_foo.com/profile.json"))
        jsonschema.validate(user_zf, USER_ZONEFILE_SCHEMA)

        subdomain.zonefile_str = blockstack_zones.make_zone_file(user_zf)

        subdomain.add_signature(sk)

        self.assertTrue(subdomain.verify_signature(pk.address()))

        parsed_zf = zonefile.decode_name_zonefile(subdomain.subdomain_name, subdomain.zonefile_str)
        urls = user_db.user_zonefile_urls(parsed_zf)

        self.assertEqual(len(urls), 1)
        self.assertIn("https://foo_foo.com/profile.json", urls)

        self.assertRaises( NotImplementedError, lambda : subdomains.encode_pubkey_entry( fake_privkey_hex ) )
示例#8
0
    def test_sigs(self):
        fake_privkey_hex = "5512612ed6ef10ea8c5f9839c63f62107c73db7306b98588a46d0cd2c3d15ea5"
        sk = keylib.ECPrivateKey(fake_privkey_hex)
        pk = sk.public_key()

        for t in ["foo", "bar", "bassoon"]:
            self.assertTrue(
                subdomains.verify(pk.address(), t, subdomains.sign(sk, t)), t)

        subdomain = subdomains.Subdomain("bar.id", "foo",
                                         subdomains.encode_pubkey_entry(sk), 3,
                                         "")

        user_zf = {'$origin': 'foo', '$ttl': 3600, 'txt': [], 'uri': []}

        user_zf['uri'].append(
            zonefile.url_to_uri_record("https://foo_foo.com/profile.json"))
        jsonschema.validate(user_zf, USER_ZONEFILE_SCHEMA)

        subdomain.zonefile_str = blockstack_zones.make_zone_file(user_zf)

        subdomain.add_signature(sk)

        self.assertTrue(subdomain.verify_signature(pk.address()))

        parsed_zf = zonefile.decode_name_zonefile(subdomain.subdomain_name,
                                                  subdomain.zonefile_str)
        urls = user_db.user_zonefile_urls(parsed_zf)

        self.assertEqual(len(urls), 1)
        self.assertIn("https://foo_foo.com/profile.json", urls)

        self.assertRaises(
            NotImplementedError,
            lambda: subdomains.encode_pubkey_entry(fake_privkey_hex))
示例#9
0
 def test_zone_file_creation_2(self):
     json_zone_file = zone_file_objects["sample_2"]
     zone_file = make_zone_file(json_zone_file)
     print(zone_file)
     self.assertTrue(isinstance(zone_file, (str, bytes)))
     self.assertTrue("$ORIGIN" in zone_file)
     self.assertTrue("$TTL" in zone_file)
     self.assertTrue("@ IN SOA" in zone_file)
示例#10
0
 def test_zone_file_creation_3(self):
     json_zone_file = zone_file_objects["sample_3"]
     zone_file = make_zone_file(json_zone_file)
     print zone_file
     self.assertTrue(isinstance(zone_file, (unicode, str)))
     self.assertTrue("$ORIGIN" in zone_file)
     self.assertTrue("$TTL" in zone_file)
     self.assertTrue("@ IN SOA" in zone_file)
示例#11
0
 def test_zone_file_creation_1(self):
     json_zone_file = zone_file_objects["sample_1"]
     zone_file = make_zone_file(json_zone_file)
     print(zone_file)
     self.assertTrue(isinstance(zone_file, (str, str)))
     self.assertTrue("$ORIGIN" in zone_file)
     self.assertTrue("$TTL" in zone_file)
     self.assertTrue("@ 1D URI" in zone_file)
示例#12
0
def hash_zonefile( zonefile_json ):
    """
    Given a JSON-ized zonefile, calculate its hash
    """
    assert "$origin" in zonefile_json.keys(), "Missing $origin"
    assert "$ttl" in zonefile_json.keys(), "Missing $ttl"

    user_zonefile_txt = blockstack_zones.make_zone_file( zonefile_json )
    data_hash = get_zonefile_data_hash( user_zonefile_txt )
    return data_hash
示例#13
0
def hash_zonefile( zonefile_json ):
    """
    Given a JSON-ized zonefile, calculate its hash
    """
    assert "$origin" in zonefile_json.keys(), "Missing $origin"
    assert "$ttl" in zonefile_json.keys(), "Missing $ttl"

    user_zonefile_txt = blockstack_zones.make_zone_file( zonefile_json )
    data_hash = get_zonefile_data_hash( user_zonefile_txt )
    return data_hash
示例#14
0
    def replicate_profile_data( cls, name_data, servers, wallet_data, storage_drivers, config_path, proxy=None ):
        """
        Given an update queue entry,
        replicate the zonefile to as many
        blockstack servers as we can.
        If given, replicate the profile as well.
        @servers should be a list of (host, port)
        Return {'status': True} on success
        Return {'error': ...} on error
        """
      
        # is the zonefile hash replicated?
        zonefile_data = name_data['zonefile']
        if zonefile_data is None:
            log.debug("No zonefile set for %s" % name_data['fqu'])
            return {'status': True}

        zonefile_hash = hash_zonefile( zonefile_data )
        name_rec = get_name_blockchain_record( name_data['fqu'], proxy=proxy )
        if 'error' in name_rec:
            return name_rec

        if str(name_rec['value_hash']) != zonefile_hash:
            log.error("Zonefile %s has not been replicated yet" % zonefile_hash)
            return {'error': 'Zonefile hash not yet replicated'}

        res = zonefile_publish( name_data['fqu'], name_data['zonefile'], servers, wallet_keys=wallet_data ) 
        if 'error' in res:
            return res

        log.info("Replicated zonefile for %s to %s server(s)" % (name_data['fqu'], len(res['servers'])))

        # replicate to our own storage providers as well 
        serialized_zonefile = blockstack_zones.make_zone_file( zonefile_data )
        rc = put_immutable_data( None, name_data['tx_hash'], data_hash=zonefile_hash, data_text=serialized_zonefile, required=storage_drivers )
        if not rc:
            log.info("Failed to replicate zonefile for %s" % (name_data['fqu']))
            return {'error': 'Failed to store user zonefile'}

        # replicate profile to storage, if given
        # use the data keypair
        if name_data.has_key('profile') and name_data['profile'] is not None:
            _, data_privkey = get_data_keypair( zonefile_data, wallet_keys=wallet_data, config_path=config_path )
            log.info("Replicate profile data for %s to %s" % (name_data['fqu'], ",".join(storage_drivers)))
            rc = put_mutable_data( name_data['fqu'], name_data['profile'], data_privkey, required=storage_drivers )
            if not rc:
                log.info("Failed to replicate profile for %s" % (name_data['fqu']))
                return {'error': 'Failed to store profile'}
            else:
                log.info("Replicated profile for %s" % (name_data['fqu']))
                return {'status': True}

        else:
            log.info("No profile to replicate for '%s'" % (name_data['fqu']))
            return {'status': True}
示例#15
0
 def test_zone_file_creation_2(self):
     json_zone_file = zone_file_objects["sample_2"]
     zone_file = make_zone_file(json_zone_file)
     print(zone_file)
     self.assertTrue(isinstance(zone_file, (str, bytes)))
     self.assertTrue("$ORIGIN" in zone_file)
     self.assertTrue("$TTL" in zone_file)
     self.assertTrue("@ IN SOA" in zone_file)
     # www has a TTL and a class
     self.assertTrue("www 3600 IN A 127.0.0.1" in zone_file)
     # mail has "_missing_class" set, confirm no class is output
     self.assertTrue("mail 3600 A 127.0.0.1" in zone_file)
示例#16
0
def store_zonefile_to_storage( zonefile_dict, required=None, skip=None, cache=False, zonefile_dir=None ):
    """
    Upload a zonefile to our storage providers.
    Return True if at least one provider got it.
    Return False otherwise.
    """

    try:
        zonefile_data = blockstack_zones.make_zone_file( zonefile_dict )
    except Exception, e:
        log.exception(e)
        log.error("Invalid zonefile dict")
        return False
def store_zonefile_to_storage( zonefile_dict, required=None, skip=None, cache=False, zonefile_dir=None ):
    """
    Upload a zonefile to our storage providers.
    Return True if at least one provider got it.
    Return False otherwise.
    """

    try:
        zonefile_data = blockstack_zones.make_zone_file( zonefile_dict )
    except Exception, e:
        log.exception(e)
        log.error("Invalid zonefile dict")
        return False
示例#18
0
def store_cached_zonefile(zonefile_dict, zonefile_dir=None):
    """
    Store a validated zonefile.
    zonefile_data should be a dict.
    The caller should first authenticate the zonefile.
    Return True on success
    Return False on error
    """
    try:
        zonefile_data = blockstack_zones.make_zone_file(zonefile_dict)
    except Exception, e:
        log.exception(e)
        log.error("Invalid zonefile dict")
        return False
def store_cached_zonefile( zonefile_dict, zonefile_dir=None ):
    """
    Store a validated zonefile.
    zonefile_data should be a dict.
    The caller should first authenticate the zonefile.
    Return True on success
    Return False on error
    """
    try:
        zonefile_data = blockstack_zones.make_zone_file( zonefile_dict )
    except Exception, e:
        log.exception(e)
        log.error("Invalid zonefile dict")
        return False
示例#20
0
def scenario( wallets, **kw ):

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

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

    testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )
   
    driver_urls = blockstack_client.storage.make_mutable_data_urls('foo.test', use_only=['dht', 'disk'])
    zonefile = blockstack_client.zonefile.make_empty_zonefile('foo.test', wallets[4].pubkey_hex, urls=driver_urls)
    zonefile_txt = blockstack_zones.make_zone_file( zonefile, origin='foo.test', ttl=3600 )

    wallet = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[2].privkey, wallets[3].privkey, None )
    resp = testlib.blockstack_cli_register( "foo.test", "0123456789abcdef", zonefile=zonefile_txt, recipient_address=wallets[4].addr )
    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):
        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):
        testlib.next_block( **kw )

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

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

    print >> sys.stderr, "Waiting 10 seconds for the backend to acknowledge transfer"
    time.sleep(10)
def make_zone_file_for_hosted_data(origin, token_file_url, ttl=3600):
    if "://" not in token_file_url:
        raise ValueError("Invalid token file URL")
    json_zone_file = {
        "$ttl": ttl,
        "$origin": origin,
        "uri": [{
            "name": "_http._tcp",
            "priority": 10,
            "weight": 1,
            "target": token_file_url
        }]
    }
    zone_file = make_zone_file(json_zone_file)
    return zone_file
示例#22
0
def zonefile_publish(fqu, zonefile_json, server_list, wallet_keys=None):
    """
    Replicate a zonefile to as many blockstack servers as possible.
    @server_list is a list of (host, port) tuple
    Return {'status': True, 'servers': ...} on success, if we succeeded to replicate at least once.
        'servers' will be a list of (host, port) tuples
    Return {'error': ...} if we failed on all accounts.
    """
    zonefile_txt = blockstack_zones.make_zone_file( zonefile_json )
    successful_servers = []
    for server_host, server_port in server_list:
        try:

            log.debug("Replicate zonefile to %s:%s" % (server_host, server_port))

            srv = BlockstackRPCClient( server_host, server_port )
            res = srv.put_zonefiles( [zonefile_txt] )
            if 'error' in res:
                log.error("Failed to publish zonefile to %s:%s: %s" % (server_host, server_port, res['error']))
                continue

            if 'status' not in res:
                log.error("Invalid server reply: no status")
                continue

            if type(res['status']) != bool or not res['status']:
                log.error("Invalid server reply: invalid status")
                continue

            if 'saved' not in res:
                log.error("Invalid server reply: no 'saved' key")
                continue

            if type(res['saved']) != list:
                log.error("Invalid server reply: no saved vector")
                continue 

            if len(res['saved']) < 1 or res['saved'][0] != 1:
                log.error("Server %s:%s failed to save zonefile" % (server_host, server_port))
                continue

            log.debug("Replicated zonefile to %s:%s" % (server_host, server_port))
            successful_servers.append( (server_host, server_port) )

        except Exception, e:
            log.exception(e)
            log.error("Failed to publish zonefile to %s:%s" % (server_host, server_port))
            continue
示例#23
0
def generate_zone_file(zone_name):
    """
    Generate a zone file containing all the records for a zone.
    """
    # Load the base records for the zone from a static zone file
    zone_base = build_zone_base_template(zone_name)
    records = parse_zone_file(zone_base)

    # Check if we are generating the zone that returns proxy A records
    proxy_domain = current_app.config["PROXY_ZONE"]
    if proxy_domain.endswith(zone_name):
        # Determine the subdomain where proxy A records will be listed
        proxy_subdomain = proxy_domain.split(zone_name)[0].strip(".")

        # Add all online entry proxies to round-robin on this subdomain
        proxy_records = select_proxy_a_records(proxy_subdomain)
        for record_type in ["a", "aaaa"]:
            records[record_type].extend(proxy_records[record_type])

    # Add all subdomains and associated TXT records for this zone
    domains = Domain.query.filter_by(zone=zone_name, deleted=False).all()
    for domain in domains:
        # Create the CNAME or ALIAS record pointing to the proxy
        record = {
            'name': domain.subdomain,
            'ttl': current_app.config["A_RECORD_TTL"]
        }
        if current_app.config.get("USE_ALIAS_RECORDS"):
            record["host"] = current_app.config["PROXY_ZONE"]
            records["alias"].append(record)
        else:
            record["alias"] = current_app.config["PROXY_ZONE"]
            records["cname"].append(record)

        # Create the TXT record with the domain->onion address mapping
        records["txt"].append({
            'name': domain.txt_label,
            'txt': "onion={}".format(domain.onion_address),
            'ttl': current_app.config["TXT_RECORD_TTL"]
        })

    # Fixes a bug in `zone_file` which places the SOA record inside a list
    records["soa"] = records["soa"].pop()

    # Bump the serial number in the SOA
    records["soa"]["serial"] = int(time.time())

    return make_zone_file(records)
示例#24
0
def make_zone_file_for_hosted_data(origin, token_file_url, ttl=3600):
    if "://" not in token_file_url:
        raise ValueError("Invalid token file URL")
    json_zone_file = {
        "$ttl":
        ttl,
        "$origin":
        origin,
        "uri": [{
            "name": "_http._tcp",
            "priority": 10,
            "weight": 1,
            "target": token_file_url
        }]
    }
    zone_file = make_zone_file(json_zone_file)
    return zone_file
def store_name_zonefile(name, user_zonefile, txid, storage_drivers=None):
    """
    Store JSON user zonefile data to the immutable storage providers, synchronously.
    This is only necessary if we've added/changed/removed immutable data.

    Return (True, hash(user zonefile)) on success
    Return (False, None) on failure
    """

    storage_drivers = [] if storage_drivers is None else storage_drivers

    assert not blockstack_profiles.is_profile_in_legacy_format(user_zonefile), 'User zonefile is a legacy profile'
    assert user_db.is_user_zonefile(user_zonefile), 'Not a user zonefile (maybe a custom legacy profile?)'

    # serialize and send off
    user_zonefile_txt = blockstack_zones.make_zone_file(user_zonefile, origin=name, ttl=USER_ZONEFILE_TTL)

    return store_name_zonefile_data(name, user_zonefile_txt, txid, storage_drivers=storage_drivers)
示例#26
0
def store_cached_zonefile( zonefile_dict, zonefile_dir=None ):
    """
    Store a validated zonefile.
    zonefile_data should be a dict.
    The caller should first authenticate the zonefile.
    Return True on success
    Return False on error
    """
    if zonefile_dir is None:
        zonefile_dir = get_zonefile_dir()

    if not os.path.exists(zonefile_dir):
        os.makedirs(zonefile_dir, 0700 )

    try:
        zonefile_data = blockstack_zones.make_zone_file( zonefile_dict )
    except Exception, e:
        log.exception(e)
        log.error("Invalid zonefile dict")
        return False
示例#27
0
def store_cached_zonefile(zonefile_dict, zonefile_dir=None):
    """
    Store a validated zonefile.
    zonefile_data should be a dict.
    The caller should first authenticate the zonefile.
    Return True on success
    Return False on error
    """
    if zonefile_dir is None:
        zonefile_dir = get_zonefile_dir()

    if not os.path.exists(zonefile_dir):
        os.makedirs(zonefile_dir, 0700)

    try:
        zonefile_data = blockstack_zones.make_zone_file(zonefile_dict)
    except Exception, e:
        log.exception(e)
        log.error("Invalid zonefile dict")
        return False
示例#28
0
def store_zonefile_to_storage( zonefile_dict, required=[] ):
    """
    Upload a zonefile to our storage providers.
    Return True if at least one provider got it.
    Return False otherwise.
    """
    zonefile_hash = hash_zonefile( zonefile_dict )
    name = zonefile_dict['$origin']
    zonefile_text = blockstack_zones.make_zone_file( zonefile_dict )
   
    # find the tx that paid for this zonefile
    txid = get_zonefile_txid( zonefile_dict )
    if txid is None:
        log.error("No txid for zonefile hash '%s' (for '%s')" % (zonefile_hash, name))
        return False
   
    rc = blockstack_client.storage.put_immutable_data( None, txid, data_hash=zonefile_hash, data_text=zonefile_text, required=required )
    if not rc:
        log.error("Failed to store zonefile '%s' (%s) for '%s'" % (zonefile_hash, txid, name))
        return False

    return True
示例#29
0
def store_name_zonefile( name, user_zonefile, txid ):
    """
    Store JSON user zonefile data to the immutable storage providers, synchronously.
    This is only necessary if we've added/changed/removed immutable data.

    Return (True, hash(user)) on success
    Return (False, None) on failure
    """

    assert not blockstack_profiles.is_profile_in_legacy_format(user_zonefile), "User zonefile is a legacy profile"
    assert user_db.is_user_zonefile(user_zonefile), "Not a user zonefile (maybe a custom legacy profile?)"

    # serialize and send off
    user_zonefile_txt = blockstack_zones.make_zone_file( user_zonefile, origin=name, ttl=USER_ZONEFILE_TTL )
    data_hash = storage.get_zonefile_data_hash( user_zonefile_txt )
    result = storage.put_immutable_data(None, txid, data_hash=data_hash, data_text=user_zonefile_txt )

    rc = None
    if result is None:
        rc = False
    else:
        rc = True

    return (rc, data_hash)
def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    wallet_keys = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[5].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 )
    
    # migrate profiles 
    res = testlib.migrate_profile( "foo.test", proxy=test_proxy, wallet_keys=wallet_keys )
    if 'error' in res:
        res['test'] = 'Failed to initialize foo.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

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

    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None)

    # make a session 
    datastore_pk = keylib.ECPrivateKey(wallets[-1].privkey).to_hex()
    res = testlib.blockstack_cli_app_signin("foo.test", datastore_pk, 'register.app', ['names', 'register', 'prices', 'zonefiles', 'blockchain', 'node_read', 'wallet_write'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

    ses = res['token']

    # for funsies, get the price of .test
    res = testlib.blockstack_REST_call('GET', '/v1/prices/namespaces/test', ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get price of .test'
        print json.dumps(res)
        return False

    test_price = res['response']['satoshis']
    print '\n\n.test costed {} satoshis\n\n'.format(test_price)

    # get the price for bar.test
    res = testlib.blockstack_REST_call('GET', '/v1/prices/names/bar.test', ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get price of bar.test'
        print json.dumps(res)
        return False

    bar_price = res['response']['total_estimated_cost']['satoshis']
    print "\n\nbar.test will cost {} satoshis\n\n".format(bar_price)

    # let's set the key to skip the transfer.

    config_dir = os.path.dirname(config_path)
     
    conf = blockstack_client.get_config(config_path)
    assert conf

    api_pass = conf['api_password']

    res = testlib.blockstack_REST_call('PUT', '/v1/wallet/keys/owner', None, api_pass=api_pass,
                                       data=new_key)
    if res['http_status'] != 200 or 'error' in res:
        print 'failed to set owner key'
        print res
        return False

  
    # make zonefile for recipient
    driver_urls = blockstack_client.storage.make_mutable_data_urls('bar.test', use_only=['dht', 'disk'])
    zonefile = blockstack_client.zonefile.make_empty_zonefile('bar.test', wallets[4].pubkey_hex, urls=driver_urls)
    zonefile_txt = blockstack_zones.make_zone_file( zonefile, origin='bar.test', ttl=3600 )

    # leaving the call format of this one the same to make sure that our registrar correctly
    #   detects that the requested TRANSFER is superfluous
    # register the name bar.test 
    res = testlib.blockstack_REST_call('POST', '/v1/names', ses, data={'name': 'bar.test', 'zonefile': zonefile_txt, 'owner_address': new_addr })
    if 'error' in res:
        res['test'] = 'Failed to register user'
        print json.dumps(res)
        error = True
        return False

    print res
    tx_hash = res['response']['transaction_hash']

    # wait for preorder to get confirmed...
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'preorder', tx_hash )
    if not res:
        return False

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

    # wait for register to go through 
    print 'Wait for register to be submitted'
    time.sleep(10)

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

    res = testlib.verify_in_queue(ses, 'bar.test', 'register', None )
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )

    print 'Wait for update to be submitted'
    time.sleep(10)

    # wait for update to get confirmed 
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'update', None )
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )
  
    print 'Wait for transfer to be submitted'
    time.sleep(10)

    # wait for transfer to get confirmed 
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'transfer', None )
    if res:
        print "Wrongly issued a TRANSFER"
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )
  
    print 'Wait for transfer to be confirmed'
    time.sleep(10)

    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test", ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    zonefile_hash = res['response']['zonefile_hash']

    # should still be registered 
    if res['response']['status'] != 'registered':
        print "register not complete"
        print json.dumps(res)
        return False

    # do we have the history for the name?
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/history", ses )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = "Failed to get name history for foo.test"
        print json.dumps(res)
        return False

    # valid history?
    hist = res['response']
    if len(hist.keys()) != 3:
        res['test'] = 'Failed to get update history'
        res['history'] = hist
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    # get the zonefile
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/zonefile/{}".format(zonefile_hash), ses )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name zonefile'
        print json.dumps(res)
        return False

    # same zonefile we put?
    if res['response']['zonefile'] != zonefile_txt:
        res['test'] = 'mismatched zonefile, expected\n{}\n'.format(zonefile_txt)
        print json.dumps(res)
        return False


    ### Now, we'll do it again, but this time, we're going to CHANGE THE KEY in the middle of registrations.
    ### to test the different paths, I'll start 3 registrations:
    # 1 has submitted preorder
    # 1 has submitted register
    # 1 has submitted update
    ### And then I'll issue a change-key


    # make zonefile for recipients
    zonefiles = []
    for i in [1,2,3]:
        name = "tricky{}.test".format(i)
        driver_urls = blockstack_client.storage.make_mutable_data_urls(name, use_only=['dht', 'disk'])
        zonefile = blockstack_client.zonefile.make_empty_zonefile(name, wallets[4].pubkey_hex, urls=driver_urls)
        zonefiles.append(blockstack_zones.make_zone_file( zonefile, origin=name, ttl=3600 ))

    # leaving the call format of this one the same to make sure that our registrar correctly
    #   detects that the requested TRANSFER is superfluous
    res = testlib.blockstack_REST_call(
        'POST', '/v1/names', ses, data={'name':'tricky1.test', 'zonefile':zonefiles[0], 'owner_address':new_addr})
    if 'error' in res:
        res['test'] = 'Failed to register tricky1.test'
        print json.dumps(res)
        error = True
        return False

    tx_hash = res['response']['transaction_hash']
    # wait for preorder to get confirmed...
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.blockstack_REST_call(
        'POST', '/v1/names', ses, data={'name':'tricky2.test', 'zonefile':zonefiles[1], 'owner_address':new_addr})
    if 'error' in res:
        res['test'] = 'Failed to register tricky2.test'
        print json.dumps(res)
        error = True
        return False

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

    # wait for register to go through
    print 'Wait for register to be submitted'
    time.sleep(10)

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

    res = testlib.blockstack_REST_call(
        'POST', '/v1/names', ses, data={'name':'tricky3.test', 'zonefile':zonefiles[2], 'owner_address':new_addr})
    if 'error' in res:
        res['test'] = 'Failed to register tricky3.test'
        print json.dumps(res)
        error = True
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )

    print 'Wait for update to be submitted'
    time.sleep(10)

    for i in xrange(0, 1):
        testlib.next_block( **kw )



    res = testlib.verify_in_queue(ses, 'tricky1.test', 'update', None)
    res = testlib.verify_in_queue(ses, 'tricky2.test', 'register', None)
    res = testlib.verify_in_queue(ses, 'tricky3.test', 'preorder', None)

    # let's go crazy.
    res = testlib.blockstack_REST_call('PUT', '/v1/wallet/keys/owner', None, api_pass=api_pass,
                                       data=insanity_key)
    if res['http_status'] != 200 or 'error' in res:
        print 'failed to set owner key'
        print res
        return False


    # wait for preorder to get confirmed
    for i in xrange(0, 6):
        testlib.next_block( **kw )
    # wake up registrar, submit register
    time.sleep(10)
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    # wake up registrar, submit update
    time.sleep(10)
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    # wake up registrar, propogate zonefile
    time.sleep(10)
def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    wallet_keys = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[5].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 )

    for i in xrange(0, 3):
        testlib.next_block( **kw )
    
    # try to preorder another namespace; it should fail
    res = testlib.blockstack_namespace_preorder( "test2", wallets[1].addr, wallets[0].privkey )
    if 'error' not in res:
        print 'accidentally succeeded to preorder test2'
        return False

    testlib.expect_snv_fail_at( "foo.test", testlib.get_current_block(**kw)+1)

    # try to reveal; it should fail 
    res = 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 )
    if 'error' not in res:
        print 'accidentally succeeded to reveal test'
        return False

    testlib.expect_snv_fail_at( "foo.test", testlib.get_current_block(**kw)+1)

    for i in xrange(0, 3):
        testlib.next_block( **kw )

    # should succeed
    res = 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 )
    if 'error' in res:
        print res
        return False

    for i in xrange(0, 3):
        testlib.next_block( **kw )

    # should fail, since we have an unusable address
    res = testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    if 'error' not in res:
        print res
        return False

    testlib.expect_snv_fail_at( "foo.test", testlib.get_current_block(**kw)+1)

    for i in xrange(0, 3):
        testlib.next_block( **kw )

    # should work now
    res = testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    if 'error' in res:
        print res
        return False

    testlib.next_block( **kw )

    testlib.blockstack_name_preorder( "foo.test", wallets[2].privkey, wallets[3].addr )
    
    for i in xrange(0, 3):
        testlib.next_block( **kw )
   
    # should fail to re-preorder, since address isn't ready
    res = testlib.blockstack_name_preorder( "foo2.test", wallets[2].privkey, wallets[3].addr )
    if 'error' not in res:
        print 'accidentally succeeded to preorder foo2.test'
        return False

    testlib.expect_snv_fail_at( "foo2.test", testlib.get_current_block(**kw)+1)

    # should fail for the same reason: the payment address is not ready
    res = testlib.blockstack_name_register( "foo.test", wallets[2].privkey, wallets[3].addr )
    if 'error' not in res:
        print 'accidentally succeeded to register foo.test'
        return False

    testlib.expect_snv_fail_at( "foo.test", testlib.get_current_block(**kw)+1)

    for i in xrange(0, 3):
        testlib.next_block( **kw )
    
    # should succeed now that it's confirmed
    res = testlib.blockstack_name_register( "foo.test", wallets[2].privkey, wallets[3].addr )
    if 'error' in res:
        print res
        return False

    for i in xrange(0, 3):
        testlib.next_block( **kw )
    
    # should fail; address not ready
    res = testlib.migrate_profile( "foo.test", proxy=test_proxy, wallet_keys=wallet_keys )
    if 'error' not in res:
        print 'accidentally succeeded to migrate profile'
        return False

    testlib.expect_snv_fail_at( "foo.test", testlib.get_current_block(**kw)+1)

    for i in xrange(0, 3):
        testlib.next_block( **kw )
    
    # migrate profiles (should succeed now) 
    res = testlib.migrate_profile( "foo.test", proxy=test_proxy, wallet_keys=wallet_keys )
    if 'error' in res:
        res['test'] = 'Failed to initialize foo.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None)

    # make a session 
    datastore_pk = keylib.ECPrivateKey(wallets[-1].privkey).to_hex()
    res = testlib.blockstack_cli_app_signin("foo.test", datastore_pk, 'register.app', ['names', 'register', 'prices', 'zonefiles', 'blockchain', 'node_read', 'wallet_read'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

    ses = res['token']
  
    # make zonefile for recipient
    driver_urls = blockstack_client.storage.make_mutable_data_urls('bar.test', use_only=['dht', 'disk'])
    zonefile = blockstack_client.zonefile.make_empty_zonefile('bar.test', wallets[4].pubkey_hex, urls=driver_urls)
    zonefile_txt = blockstack_zones.make_zone_file( zonefile, origin='bar.test', ttl=3600 )

    # register the name bar.test (no zero-conf, should fail)
    res = testlib.blockstack_REST_call('POST', '/v1/names', ses, data={'name': 'bar.test', 'zonefile': zonefile_txt, 'owner_address': wallets[4].addr})
    if res['http_status'] == 200:
        print 'accidentally succeeded to register bar.test'
        print res
        return False

    # let's test /v1/wallet/balance
    res = testlib.blockstack_REST_call('GET', '/v1/wallet/balance', ses)
    if res['http_status'] != 200:
        print '/v1/wallet/balance returned ERR'
        print json.dumps(res)
        return False
    if res['response']['balance']['satoshis'] > 0:
        print '/v1/wallet/balance accidentally incorporated 0-conf txns in balance register bar.test'
        print json.dumps(res['response'])
        return False

    # let's test /v1/wallet/balance with minconfs=0
    res = testlib.blockstack_REST_call('GET', '/v1/wallet/balance/0', ses)
    if res['http_status'] != 200:
        print '/v1/wallet/balance/0 returned ERR'
        print json.dumps(res)
        return False
    if res['response']['balance']['satoshis'] < 1e6:
        print "/v1/wallet/balance/0 didn't incorporate 0-conf txns"
        print json.dumps(res['response'])
        return False

    # register the name bar.test (1-conf, should fail)
    res = testlib.blockstack_REST_call('POST', '/v1/names', ses, data={'name': 'bar.test', 'zonefile': zonefile_txt, 'owner_address': wallets[4].addr, 'min_confs' : 1})
    if res['http_status'] == 200:
        print 'accidentally succeeded to register bar.test'
        print res
        return False

    # register the name bar.test (zero-conf, should succeed)
    res = testlib.blockstack_REST_call('POST', '/v1/names', ses, data={'name': 'bar.test', 'zonefile': zonefile_txt, 'owner_address': wallets[4].addr, 'min_confs': 0})
    if 'error' in res:
        res['test'] = 'Failed to register user'
        print json.dumps(res)
        error = True
        return False

    print res
    tx_hash = res['response']['transaction_hash']

    # wait for preorder to get confirmed...
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'preorder', tx_hash )
    if not res:
        return False

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

    # wait for register to go through 
    print 'Wait for register to be submitted'
    time.sleep(10)

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

    res = testlib.verify_in_queue(ses, 'bar.test', 'register', None )
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )

    print 'Wait for update to be submitted'
    time.sleep(10)

    # wait for update to get confirmed 
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'update', None )
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )
  
    print 'Wait for transfer to be submitted'
    time.sleep(10)

    # wait for transfer to get confirmed 
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'transfer', None )
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )
  
    print 'Wait for transfer to be confirmed'
    time.sleep(10)

    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test", ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    zonefile_hash = res['response']['zonefile_hash']

    # should still be registered 
    if res['response']['status'] != 'registered':
        print "register not complete"
        print json.dumps(res)
        return False

    # do we have the history for the name?
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/history", ses )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = "Failed to get name history for foo.test"
        print json.dumps(res)
        return False

    # valid history?
    hist = res['response']
    if len(hist.keys()) != 4:
        res['test'] = 'Failed to get update history'
        res['history'] = hist
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    # get the zonefile
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/zonefile/{}".format(zonefile_hash), ses )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name zonefile'
        print json.dumps(res)
        return False

    # same zonefile we put?
    if res['response']['zonefile'] != zonefile_txt:
        res['test'] = 'mismatched zonefile, expected\n{}\n'.format(zonefile_txt)
        print json.dumps(res)
        return False
def scenario( wallets, **kw ):

    global synchronized, value_hash

    import blockstack_integration_tests.atlas_network as atlas_network

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

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

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

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

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

    # register 10 names
    for i in xrange(0, 10):
        res = testlib.blockstack_name_preorder( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr )
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block( **kw )
    
    for i in xrange(0, 10):
        res = testlib.blockstack_name_register( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr )
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block( **kw )
    
    # make 10 empty zonefiles and propagate them 
    for i in xrange(0, 10):
        data_pubkey = virtualchain.BitcoinPrivateKey(wallet_keys['data_privkey']).public_key().to_hex()
        empty_zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo_{}.test".format(i), data_pubkey, urls=["file:///tmp/foo_{}.test".format(i)] )
        empty_zonefile_str = blockstack_zones.make_zone_file( empty_zonefile )
        value_hash = blockstack_client.hash_zonefile( empty_zonefile )

        res = testlib.blockstack_name_update( "foo_{}.test".format(i), value_hash, wallets[3].privkey )
        if 'error' in res:
            print json.dumps(res)
            return False

        testlib.next_block( **kw )

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

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

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

    global value_hashes

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

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

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

    # register 10 names
    for i in xrange(0, 10):
        res = testlib.blockstack_name_preorder( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr )
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block( **kw )
    
    for i in xrange(0, 10):
        res = testlib.blockstack_name_register( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr )
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block( **kw )
 
    # make 10 empty zonefiles and propagate them 
    for i in xrange(0, 10):
        data_pubkey = wallets[4].pubkey_hex
        empty_zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo_{}.test".format(i), data_pubkey, urls=["file:///tmp/foo_{}.test".format(i)] )
        empty_zonefile_str = blockstack_zones.make_zone_file( empty_zonefile )
        value_hash = blockstack_client.hash_zonefile( empty_zonefile )

        res = testlib.blockstack_name_update( "foo_{}.test".format(i), value_hash, wallets[3].privkey )
        if 'error' in res:
            print json.dumps(res)
            return False

        testlib.next_block( **kw )

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

        value_hashes.append(value_hash)

    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG")
    assert config_path
    restore_dir = os.path.join(os.path.dirname(config_path), "snapshot_dir")

    # snapshot the latest backup
    snapshot_path = os.path.join( os.path.dirname(config_path), "snapshot.bsk" )
    rc = blockstack.fast_sync_snapshot( snapshot_path, wallets[3].privkey, None )
    if not rc:
        print "Failed to fast_sync_snapshot"
        return False
   
    if not os.path.exists(snapshot_path):
        print "Failed to create snapshot {}".format(snapshot_path)
        return False

    # sign with more keys 
    for i in xrange(4, 6):
        rc = blockstack.fast_sync_sign_snapshot( snapshot_path, wallets[i].privkey )
        if not rc:
            print "Failed to sign with key {}".format(i)
            return False

    # restore!
    rc = restore( snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[4].pubkey_hex, wallets[5].pubkey_hex], 3 )
    if not rc:
        print "failed to restore snapshot {}".format(snapshot_path)
        return False

    rc = restore( snapshot_path, restore_dir, [wallets[5].pubkey_hex, wallets[4].pubkey_hex, wallets[3].pubkey_hex], 3 )
    if not rc:
        print "failed to restore snapshot {}".format(snapshot_path)
        return False

    rc = restore( snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[4].pubkey_hex], 2 )
    if not rc:
        print "failed to restore snapshot {}".format(snapshot_path)
        return False

    rc = restore( snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[5].pubkey_hex], 2 )
    if not rc:
        print "failed to restore snapshot {}".format(snapshot_path)
        return False

    rc = restore( snapshot_path, restore_dir, [wallets[4].pubkey_hex, wallets[5].pubkey_hex], 2 )
    if not rc:
        print "failed to restore snapshot {}".format(snapshot_path)
        return False

    rc = restore( snapshot_path, restore_dir, [wallets[3].pubkey_hex], 1 )
    if not rc:
        print "failed to restore snapshot {}".format(snapshot_path)
        return False

    rc = restore( snapshot_path, restore_dir, [wallets[4].pubkey_hex, wallets[0].pubkey_hex], 1 )
    if not rc:
        print "failed to restore snapshot {}".format(snapshot_path)
        return False

    rc = restore( snapshot_path, restore_dir, [wallets[0].pubkey_hex, wallets[1].pubkey_hex, wallets[5].pubkey_hex], 1 )
    if not rc:
        print "failed to restore snapshot {}".format(snapshot_path)
        return False

    # should fail
    rc = restore( snapshot_path, restore_dir, [wallets[3].pubkey_hex], 2 )
    if rc:
        print "restored insufficient signatures snapshot {}".format(snapshot_path)
        return False

    shutil.rmtree(restore_dir)

    # should fail
    rc = restore( snapshot_path, restore_dir, [wallets[3].pubkey_hex, wallets[4].pubkey_hex], 3 )
    if rc:
        print "restored insufficient signatures snapshot {}".format(snapshot_path)
        return False

    shutil.rmtree(restore_dir)

    # should fail
    rc = restore( snapshot_path, restore_dir, [wallets[0].pubkey_hex], 1 )
    if rc:
        print "restored wrongly-signed snapshot {}".format(snapshot_path)
        return False

    shutil.rmtree(restore_dir)

    # should fail
    rc = restore( snapshot_path, restore_dir, [wallets[0].pubkey_hex, wallets[3].pubkey_hex], 2 )
    if rc:
        print "restored wrongly-signed snapshot {}".format(snapshot_path)
        return False

    shutil.rmtree(restore_dir)

    # should fail
    rc = restore( snapshot_path, restore_dir, [wallets[0].pubkey_hex, wallets[3].pubkey_hex, wallets[4].pubkey_hex], 3 )
    if rc:
        print "restored wrongly-signed snapshot {}".format(snapshot_path)
        return False

    shutil.rmtree(restore_dir)
示例#34
0
def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    wallet_keys = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[5].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 )

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

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

    testlib.next_block( **kw )

    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None)

    # make a session
    datastore_pk = keylib.ECPrivateKey(wallets[-1].privkey).to_hex()
    res = testlib.blockstack_cli_app_signin("foo.test", datastore_pk, 'register.app', ['names', 'register', 'prices', 'zonefiles', 'blockchain', 'node_read', 'wallet_write'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    ses = res['token']

    # let's set the key to skip the transfer.

    config_dir = os.path.dirname(config_path)
    conf = blockstack_client.get_config(config_path)
    assert conf

    api_pass = conf['api_password']

    new_payment_key = {
        'private_key' : wallets[1].privkey,
        'persist_change' : True
    }

    res = testlib.blockstack_REST_call('PUT', '/v1/wallet/keys/payment', None, api_pass=api_pass,
                                       data=new_payment_key)
    if res['http_status'] != 200 or 'error' in res:
        print 'failed to set payment key'
        print res
        return False


    testlib.stop_api()
    testlib.start_api('0123456789abcdef')

    res = testlib.blockstack_REST_call('GET', '/v1/wallet/payment_address', None, api_pass = api_pass)
    if res['http_status'] != 200 or 'error' in res:
        res['test'] = 'Failed to get payment address'
        print res
        return False
    if res['response']['address'] != wallets[1].addr:
        res['test'] = 'Got wrong payer address, expected {}, got {}'.format(
            wallets[1].addr, res['response']['address'])
        print res
        return False

    res = testlib.blockstack_REST_call('PUT', '/v1/wallet/keys/owner', None, api_pass=api_pass,
                                       data=new_key)
    if res['http_status'] != 200 or 'error' in res:
        print 'failed to set owner key'
        print res
        return False


    # make zonefile for recipient
    driver_urls = blockstack_client.storage.make_mutable_data_urls('bar.test', use_only=['dht', 'disk'])
    zonefile = blockstack_client.zonefile.make_empty_zonefile('bar.test', wallets[4].pubkey_hex, urls=driver_urls)
    zonefile_txt = blockstack_zones.make_zone_file( zonefile, origin='bar.test', ttl=3600 )

    # leaving the call format of this one the same to make sure that our registrar correctly
    #   detects that the requested TRANSFER is superfluous
    # register the name bar.test
    res = testlib.blockstack_REST_call('POST', '/v1/names', ses, data={'name': 'bar.test', 'zonefile': zonefile_txt, 'owner_address': new_addr })
    if 'error' in res:
        res['test'] = 'Failed to register user'
        print json.dumps(res)
        error = True
        return False

    print res
    tx_hash = res['response']['transaction_hash']

    # wait for preorder to get confirmed...
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'preorder', tx_hash )
    if not res:
        return False

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

    # wait for register to go through
    print 'Wait for register to be submitted'
    time.sleep(10)

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

    res = testlib.verify_in_queue(ses, 'bar.test', 'register', None )
    if not res:
        return False

    for i in xrange(0, 4):
        testlib.next_block( **kw )

    print 'Wait for update to be submitted'
    time.sleep(10)

    # wait for update to get confirmed
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'update', None )
    if not res:
        return False

    for i in xrange(0, 4):
        testlib.next_block( **kw )

    print 'Wait for transfer to be submitted'
    time.sleep(10)

    # wait for transfer to get confirmed
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'transfer', None )
    if res:
        print res
        print "Wrongly issued a TRANSFER"
        return False

    for i in xrange(0, 4):
        testlib.next_block( **kw )

    print 'Wait for transfer to be confirmed'
    time.sleep(10)

    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test", ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    zonefile_hash = res['response']['zonefile_hash']

    # should still be registered
    if res['response']['status'] != 'registered':
        print "register not complete"
        print json.dumps(res)
        return False

    # do we have the history for the name?
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/history", ses )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = "Failed to get name history for foo.test"
        print json.dumps(res)
        return False

    # valid history?
    hist = res['response']
    if len(hist.keys()) != 3:
        res['test'] = 'Failed to get update history'
        res['history'] = hist
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    # get the zonefile
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/zonefile/{}".format(zonefile_hash), ses )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name zonefile'
        print json.dumps(res)
        return False

    # same zonefile we put?
    if res['response']['zonefile'] != zonefile_txt:
        res['test'] = 'mismatched zonefile, expected\n{}\n'.format(zonefile_txt)
        print json.dumps(res)
        return False
示例#35
0
def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    wallet_keys = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[5].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 )

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

    testlib.next_block( **kw )

    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None)

    # make a session
    datastore_pk = keylib.ECPrivateKey(wallets[-1].privkey).to_hex()
    res = testlib.blockstack_cli_app_signin("foo.test", datastore_pk, 'register.app', ['names', 'register', 'prices', 'zonefiles', 'blockchain', 'node_read', 'wallet_write'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    ses = res['token']

    # my own KEYS

    owner_key = new_key

    config_dir = os.path.dirname(config_path)
    conf = blockstack_client.get_config(config_path)
    assert conf

    api_pass = conf['api_password']

    payment_key = wallets[1].privkey
    payer = wallets[1].addr

    # make zonefile for recipient
    driver_urls = blockstack_client.storage.make_mutable_data_urls('bar.test', use_only=['dht', 'disk'])
    zonefile = blockstack_client.zonefile.make_empty_zonefile('bar.test', wallets[4].pubkey_hex, urls=driver_urls)
    zonefile_txt = blockstack_zones.make_zone_file( zonefile, origin='bar.test', ttl=3600 )


    postage = {'name': 'bar.test', 'zonefile': zonefile_txt, 'owner_address': new_addr,
               'payment_key' : payment_key, 'owner_key' : owner_key}

    # leaving the call format of this one the same to make sure that our registrar correctly
    #   detects that the requested TRANSFER is superfluous
    # register the name bar.test
    res = testlib.blockstack_REST_call('POST', '/v1/names', ses, data=postage)
    if 'error' in res:
        res['test'] = 'Failed to register user'
        print json.dumps(res)
        error = True
        return False

    print res
    tx_hash = res['response']['transaction_hash']

    # wait for preorder to get confirmed...
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'preorder', tx_hash )
    if not res:
        return False

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

    # wait for register to go through
    print 'Wait for register to be submitted'
    time.sleep(10)

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

    res = testlib.verify_in_queue(ses, 'bar.test', 'register', None )
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )

    print 'Wait for update to be submitted'
    time.sleep(10)

    # wait for update to get confirmed
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'update', None )
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )

    print 'Wait for transfer to be submitted'
    time.sleep(10)

    # wait for transfer to get confirmed
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'transfer', None )
    if res:
        print "Wrongly issued a TRANSFER"
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )

    print 'Wait for transfer to be confirmed'
    time.sleep(10)

    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test", ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    zonefile_hash = res['response']['zonefile_hash']

    # should still be registered
    if res['response']['status'] != 'registered':
        print "register not complete"
        print json.dumps(res)
        return False

    # do we have the history for the name?
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/history", ses )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = "Failed to get name history for foo.test"
        print json.dumps(res)
        return False

    # valid history?
    hist = res['response']
    if len(hist.keys()) != 3:
        res['test'] = 'Failed to get update history'
        res['history'] = hist
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    # get the zonefile
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/zonefile/{}".format(zonefile_hash), ses )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name zonefile'
        print json.dumps(res)
        return False

    # same zonefile we put?
    if res['response']['zonefile'] != zonefile_txt:
        res['test'] = 'mismatched zonefile, expected\n{}\n'.format(zonefile_txt)
        print json.dumps(res)
        return False


    ### Now, we'll do it again, but this time, we're going to CHANGE THE KEY in the middle of registrations.
    ### to test the different paths, I'll start 3 registrations:
    # 1 has submitted preorder
    # 1 has submitted register
    # 1 has submitted update
    ### And then I'll issue a change-key


    # make zonefile for recipients
    zonefiles = []
    postages = []
    for i in [1,2,3]:
        name = "tricky{}.test".format(i)
        driver_urls = blockstack_client.storage.make_mutable_data_urls(name, use_only=['dht', 'disk'])
        zonefile = blockstack_client.zonefile.make_empty_zonefile(name, wallets[4].pubkey_hex, urls=driver_urls)
        zf_txt = blockstack_zones.make_zone_file( zonefile, origin=name, ttl=3600 )
        zonefiles.append(zf_txt)
        postages.append(
            {'name': name, 'zonefile' : zf_txt, 'owner_address': new_addr,
             'payment_key' : payment_key, 'owner_key' : owner_key})

    res = testlib.blockstack_REST_call('POST', '/v1/names', ses, data=postages[0])
    if 'error' in res:
        res['test'] = 'Failed to register tricky1.test'
        print json.dumps(res)
        error = True
        return False

    tx_hash = res['response']['transaction_hash']
    # wait for preorder to get confirmed...
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.blockstack_REST_call('POST', '/v1/names', ses, data=postages[1])
    if 'error' in res:
        res['test'] = 'Failed to register tricky2.test'
        print json.dumps(res)
        error = True
        return False

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

    # wait for register to go through
    print 'Wait for register to be submitted'
    time.sleep(10)

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

    res = testlib.blockstack_REST_call('POST', '/v1/names', ses, data=postages[2])
    if 'error' in res:
        res['test'] = 'Failed to register tricky3.test'
        print json.dumps(res)
        error = True
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )

    print 'Wait for update to be submitted'
    time.sleep(10)

    for i in xrange(0, 1):
        testlib.next_block( **kw )



    res = testlib.verify_in_queue(ses, 'tricky1.test', 'update', None)
    res = testlib.verify_in_queue(ses, 'tricky2.test', 'register', None)
    res = testlib.verify_in_queue(ses, 'tricky3.test', 'preorder', None)

    # let's go crazy.
    res = testlib.blockstack_REST_call('PUT', '/v1/wallet/keys/owner', None, api_pass=api_pass,
                                       data=insanity_key)
    res = testlib.blockstack_REST_call('PUT', '/v1/wallet/keys/payment', None, api_pass=api_pass,
                                       data=insanity_key)
    if res['http_status'] != 200 or 'error' in res:
        print 'failed to set owner key'
        print res
        return False


    # wait for preorder to get confirmed
    for i in xrange(0, 6):
        testlib.next_block( **kw )
    # wake up registrar, submit register
    time.sleep(10)
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    # wake up registrar, submit update
    time.sleep(10)
    for i in xrange(0, 12):
        testlib.next_block( **kw )
    # wake up registrar, propogate zonefile
    time.sleep(10)
示例#36
0
def scenario(wallets, **kw):

    global synchronized, value_hash

    import blockstack_integration_tests.atlas_network as atlas_network

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

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

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

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

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

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

    # register 10 names
    for i in xrange(0, 10):
        res = testlib.blockstack_name_preorder("foo_{}.test".format(i),
                                               wallets[2].privkey,
                                               wallets[3].addr)
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block(**kw)

    for i in xrange(0, 10):
        res = testlib.blockstack_name_register("foo_{}.test".format(i),
                                               wallets[2].privkey,
                                               wallets[3].addr)
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block(**kw)

    # make 10 empty zonefiles and propagate them
    for i in xrange(0, 10):
        data_pubkey = virtualchain.BitcoinPrivateKey(
            wallet_keys['data_privkey']).public_key().to_hex()
        empty_zonefile = blockstack_client.zonefile.make_empty_zonefile(
            "foo_{}.test".format(i),
            data_pubkey,
            urls=["file:///tmp/foo_{}.test".format(i)])
        empty_zonefile_str = blockstack_zones.make_zone_file(empty_zonefile)
        value_hash = blockstack_client.hash_zonefile(empty_zonefile)

        res = testlib.blockstack_name_update("foo_{}.test".format(i),
                                             value_hash, wallets[3].privkey)
        if 'error' in res:
            print json.dumps(res)
            return False

        testlib.next_block(**kw)

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

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

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

        host, port = 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 60 seconds for the altas peers to catch up"
    time.sleep(60.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
示例#37
0
def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    wallet_keys = testlib.blockstack_client_initialize_wallet(
        "0123456789abcdef", wallets[5].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 )

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

    testlib.next_block( **kw )

    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None)

    # let's set the key to skip the transfer.
    config_dir = os.path.dirname(config_path)
    conf = blockstack_client.get_config(config_path)
    assert conf

    api_pass = conf['api_password']

    res = testlib.blockstack_REST_call('PUT', '/v1/wallet/keys/owner', None, api_pass=api_pass,
                                       data=new_key)
    if res['http_status'] != 200 or 'error' in res:
        print 'failed to set owner key'
        print res
        return False

    # make zonefile for recipient
    driver_urls = blockstack_client.storage.make_mutable_data_urls('bar.test', use_only=['dht', 'disk'])
    zonefile = blockstack_client.zonefile.make_empty_zonefile('bar.test', wallets[4].pubkey_hex, urls=driver_urls)
    zonefile_txt = blockstack_zones.make_zone_file( zonefile, origin='bar.test', ttl=3600 )

    # leaving the call format of this one the same to make sure that our registrar correctly
    #   detects that the requested TRANSFER is superfluous
    # register the name bar.test
    res = testlib.blockstack_REST_call(
        'POST', '/v1/names', None, api_pass=api_pass, data={
            'name': 'bar.test', 'zonefile': zonefile_txt, 'owner_address': new_addr
        })
    if 'error' in res:
        res['test'] = 'Failed to register user'
        print json.dumps(res)
        error = True
        return False

    print res
    tx_hash = res['response']['transaction_hash']

    # wait for preorder to get confirmed...
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(None, 'bar.test', 'preorder', tx_hash, api_pass = api_pass )
    if not res:
        return False

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

    # wait for register to go through
    print 'Wait for register to be submitted'
    time.sleep(10)

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

    res = testlib.verify_in_queue(None, 'bar.test', 'register', None, api_pass = api_pass )
    if not res:
        return False

    for i in xrange(0, 4):
        testlib.next_block( **kw )

    print 'Wait for update to be submitted'
    time.sleep(10)

    # wait for update to get confirmed
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(None, 'bar.test', 'update', None, api_pass = api_pass )
    if not res:
        print res
        print "update error in first update"
        return False

    for i in xrange(0, 4):
        testlib.next_block( **kw )

    print 'Wait for transfer to be submitted'
    time.sleep(10)

    # wait for transfer to get confirmed
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(None, 'bar.test', 'transfer', None, api_pass = api_pass )
    if res:
        print "Wrongly issued a TRANSFER"
        return False

    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test",
                                       None, api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    zonefile_hash = res['response']['zonefile_hash']

    # should still be registered
    if res['response']['status'] != 'registered':
        print "register not complete"
        print json.dumps(res)
        return False

    # do we have the history for the name?
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/history",
                                       None, api_pass=api_pass )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = "Failed to get name history for foo.test"
        print json.dumps(res)
        return False

    # valid history?
    hist = res['response']
    if len(hist.keys()) != 3:
        res['test'] = 'Failed to get update history'
        res['history'] = hist
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    # get the zonefile
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/zonefile/{}".format(zonefile_hash),
                                       None, api_pass=api_pass )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name zonefile'
        print json.dumps(res)
        return False

    # same zonefile we put?
    if res['response']['zonefile'] != zonefile_txt:
        res['test'] = 'mismatched zonefile, expected\n{}\n'.format(zonefile_txt)
        print json.dumps(res)
        return False

    # okay, now let's try to do a transfer.
    # FIRST, I want to change the key to a key that
    #  doesn't own the name and a payment key that has no money
    res = testlib.blockstack_REST_call('PUT', '/v1/wallet/keys/owner', None, api_pass=api_pass,
                                       data=insanity_key)
    if res['http_status'] != 200 or 'error' in res:
        print 'failed to set owner key'
        print res
        return False

    res = testlib.blockstack_REST_call('PUT', '/v1/wallet/keys/payment', None, api_pass=api_pass,
                                       data=insanity_key)
    if res['http_status'] != 200 or 'error' in res:
        print 'failed to set owner key'
        print res
        return False

    payment_key = wallets[1].privkey

    # let's do this with the bad key
    res = testlib.blockstack_REST_call(
        'PUT', '/v1/names/bar.test/owner', None, api_pass=api_pass, data={
            'owner': destination_owner, 'payment_key' : payment_key
        })
    if 'error' in res or res['http_status'] != 202:
        res['test'] = '(Correctly) failed to transfer user'
        print json.dumps(res)


    # let's do this with the good one!
    res = testlib.blockstack_REST_call(
        'PUT', '/v1/names/bar.test/owner', None, api_pass=api_pass, data={
            'owner': destination_owner, 'owner_key' : new_key,
            'payment_key' : payment_key
        })
    if 'error' in res or res['http_status'] != 202:
        res['test'] = '(Wrongly) failed to transfer user'
        print json.dumps(res)
        error = True
        return False
    else:
        print "Submitted transfer!"
        print res

    print 'Wait for transfer to be submitted'
    time.sleep(10)

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

    res = testlib.verify_in_queue(None, 'bar.test', 'transfer', None, api_pass = api_pass )
    if not res:
        print "transfer error"
        print res
        return False

    for i in xrange(0, 4):
        testlib.next_block( **kw )

    # wait for zonefile to propagate
    time.sleep(10)

    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test",
                                       None, api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    cur_owner_address = res['response']['address']
    if cur_owner_address != destination_owner:
        print "After transfer, unexpected owner. Expected {}, Actual {}".format(
            destination_owner, cur_owner_address)
        return False
示例#38
0
def scenario(wallets, **kw):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    empty_key = ECPrivateKey().to_hex()

    wallet_keys = testlib.blockstack_client_initialize_wallet(
        "0123456789abcdef", empty_key, empty_key, empty_key)
    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)

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

    testlib.next_block(**kw)

    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None)

    config_dir = os.path.dirname(config_path)
    conf = blockstack_client.get_config(config_path)
    assert conf

    api_pass = conf['api_password']

    payment_key = wallets[1].privkey

    # make zonefile for recipient
    driver_urls = blockstack_client.storage.make_mutable_data_urls(
        'bar.test', use_only=['dht', 'disk'])
    zonefile = blockstack_client.zonefile.make_empty_zonefile(
        'bar.test', wallets[4].pubkey_hex, urls=driver_urls)
    zonefile_txt = blockstack_zones.make_zone_file(zonefile,
                                                   origin='bar.test',
                                                   ttl=3600)

    no_key_postage = {'name': 'bar.test', 'zonefile': zonefile_txt}
    key_postage = dict(no_key_postage)
    key_postage['payment_key'] = payment_key
    key_postage['owner_key'] = new_key

    res = testlib.blockstack_REST_call('POST',
                                       '/v1/names',
                                       None,
                                       api_pass=api_pass,
                                       data=no_key_postage)
    if 'error' not in res['response']:
        print "Successfully registered user with should-have-been-bad keys"
        print res
        return False

    # let's do a small withdraw
    res = testlib.blockstack_REST_call(
        'POST',
        '/v1/wallet/balance',
        None,
        api_pass=api_pass,
        data={
            'address': virtualchain.get_privkey_address(empty_key),
            'amount': int(1e4),
            'payment_key': payment_key
        })
    if 'error' in res['response']:
        res['test'] = 'Failed to perform withdraw'
        print json.dumps(res)
        error = True
        return False
    for i in xrange(0, 1):
        testlib.next_block(**kw)
    print 'Waiting for the withdraw to go through'
    res = testlib.blockstack_REST_call('GET',
                                       '/v1/wallet/balance/0',
                                       None,
                                       api_pass=api_pass)
    if 'error' in res['response']:
        res['test'] = 'Failed to get wallet balance'
        print json.dumps(res)
        error = True
        return False

    if int(res['response']['balance']['satoshis']) <= 0:
        res['test'] = 'Wallet balance did not increment!'
        print json.dumps(res)
        error = True
        return False

    res = testlib.blockstack_REST_call('POST',
                                       '/v1/names',
                                       None,
                                       api_pass=api_pass,
                                       data=key_postage)
    if 'error' in res['response']:
        res['test'] = 'Failed to register user'
        print json.dumps(res)
        error = True
        return False

    print "Registering bar.test"
    for i in xrange(0, 6):
        testlib.next_block(**kw)
    if not res:
        return False
    # wait for the preorder to get confirmed
    for i in xrange(0, 6):
        testlib.next_block(**kw)
    # wait for register to go through
    print 'Wait for register to be submitted'
    time.sleep(10)
    # wait for the register to get confirmed
    for i in xrange(0, 6):
        testlib.next_block(**kw)
    res = testlib.verify_in_queue(None,
                                  'bar.test',
                                  'register',
                                  None,
                                  api_pass=api_pass)
    if not res:
        return False
    for i in xrange(0, 6):
        testlib.next_block(**kw)
    print 'Wait for update to be submitted'
    time.sleep(10)
    # wait for update to get confirmed
    for i in xrange(0, 6):
        testlib.next_block(**kw)
    res = testlib.verify_in_queue(None,
                                  'bar.test',
                                  'update',
                                  None,
                                  api_pass=api_pass)
    if not res:
        print res
        print "update error in first update"
        return False
    for i in xrange(0, 6):
        testlib.next_block(**kw)

    res = testlib.blockstack_REST_call("GET",
                                       "/v1/names/bar.test",
                                       None,
                                       api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    zonefile_hash = res['response']['zonefile_hash']

    # should still be registered
    if res['response']['status'] != 'registered':
        print "register not complete"
        print json.dumps(res)
        return False

    # do we have the history for the name?
    res = testlib.blockstack_REST_call("GET",
                                       "/v1/names/bar.test/history",
                                       None,
                                       api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = "Failed to get name history for foo.test"
        print json.dumps(res)
        return False

    # valid history?
    hist = res['response']
    if len(hist.keys()) != 3:
        res['test'] = 'Failed to get update history'
        res['history'] = hist
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    # get the zonefile
    res = testlib.blockstack_REST_call(
        "GET",
        "/v1/names/bar.test/zonefile/{}".format(zonefile_hash),
        None,
        api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name zonefile'
        print json.dumps(res)
        return False

    # same zonefile we put?
    if res['response']['zonefile'] != zonefile_txt:
        res['test'] = 'mismatched zonefile, expected\n{}\n'.format(
            zonefile_txt)
        print json.dumps(res)
        return False

    # okay, now let's try to do an update.
    # make zonefile for recipient
    driver_urls = blockstack_client.storage.make_mutable_data_urls(
        'bar.test', use_only=['http', 'disk'])
    zonefile = blockstack_client.zonefile.make_empty_zonefile(
        'bar.test', wallets[3].pubkey_hex, urls=driver_urls)
    zonefile_txt = blockstack_zones.make_zone_file(zonefile,
                                                   origin='bar.test',
                                                   ttl=3600)

    # let's do this update.
    res = testlib.blockstack_REST_call('PUT',
                                       '/v1/names/bar.test/zonefile',
                                       None,
                                       api_pass=api_pass,
                                       data={
                                           'zonefile': zonefile_txt,
                                           'owner_key': new_key,
                                           'payment_key': payment_key
                                       })
    if 'error' in res or res['http_status'] != 202:
        res['test'] = 'Failed to register user'
        print json.dumps(res)
        error = True
        return False
    else:
        print "Submitted update!"
        print res

    print 'Wait for update to be submitted'
    time.sleep(10)

    # wait for update to get confirmed
    for i in xrange(0, 6):
        testlib.next_block(**kw)

    res = testlib.verify_in_queue(None,
                                  'bar.test',
                                  'update',
                                  None,
                                  api_pass=api_pass)
    if not res:
        print "update error in second update"
        print res
        return False

    for i in xrange(0, 6):
        testlib.next_block(**kw)

    # wait for zonefile to propagate
    time.sleep(10)

    res = testlib.blockstack_REST_call("GET",
                                       "/v1/names/bar.test",
                                       None,
                                       api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    zonefile_hash = res['response']['zonefile_hash']
    # get the zonefile
    res = testlib.blockstack_REST_call(
        "GET",
        "/v1/names/bar.test/zonefile/{}".format(zonefile_hash),
        None,
        api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name zonefile'
        print json.dumps(res)
        return False

    # same zonefile we put?
    if res['response']['zonefile'] != zonefile_txt:
        res['test'] = 'mismatched zonefile, expected\n{}\n'.format(
            zonefile_txt)
        print json.dumps(res)
        return False
def scenario(wallets, **kw):

    global synchronized, value_hash

    import blockstack_integration_tests.atlas_network as atlas_network

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

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

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

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

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

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

    # register 10 names
    for i in xrange(0, 10):
        res = testlib.blockstack_name_preorder("foo_{}.test".format(i),
                                               wallets[2].privkey,
                                               wallets[3].addr)
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block(**kw)

    for i in xrange(0, 10):
        res = testlib.blockstack_name_register("foo_{}.test".format(i),
                                               wallets[2].privkey,
                                               wallets[3].addr)
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block(**kw)

    # make 10 empty zonefiles and propagate them
    for i in xrange(0, 10):
        data_pubkey = virtualchain.BitcoinPrivateKey(
            wallet_keys['data_privkey']).public_key().to_hex()
        empty_zonefile = blockstack_client.zonefile.make_empty_zonefile(
            "foo_{}.test".format(i),
            data_pubkey,
            urls=["file:///tmp/foo_{}.test".format(i)])
        empty_zonefile_str = blockstack_zones.make_zone_file(empty_zonefile)
        value_hash = blockstack_client.hash_zonefile(empty_zonefile)

        res = testlib.blockstack_name_update("foo_{}.test".format(i),
                                             value_hash, wallets[3].privkey)
        if 'error' in res:
            print json.dumps(res)
            return False

        testlib.next_block(**kw)

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

    # start up an atlas network with 16 peers, 8 of which will be active at once.
    # every second, have one peer come online, and one peer go offline.
    # have them all start out knowing about the same seed node.
    atlas_nodes = [
        17000, 17001, 17002, 17003, 17004, 17005, 17006, 17007, 17008, 17009,
        17010, 17011, 17012, 17013, 17014, 17015, 17016
    ]
    atlas_topology = {}
    for i in xrange(0, 9):
        atlas_topology[atlas_nodes[i]] = [16264]

    for i in xrange(9, len(atlas_nodes)):
        atlas_topology[atlas_nodes[i]] = [17008]

    atlas_topology[atlas_nodes[-1]].append(16264)

    # put the seed after the first four
    all_peers = atlas_nodes[:4] + [16264] + atlas_nodes[4:]

    time_start = int(time.time()) + 60

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

        src_host, src_port = 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 60 seconds for the altas peers to catch up"
    time.sleep(60.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
    def test_db_builder_bad_transitions(self):
        history = [
            """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
foo TXT "owner={}" "seqn=0" "parts=0"
""",
            """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
bar TXT "owner={}" "seqn=0" "parts=0"
""",
]

        foo_bar_sk = keylib.ECPrivateKey()
        bar_bar_sk = keylib.ECPrivateKey()

        history[0] = history[0].format(subdomains.encode_pubkey_entry(foo_bar_sk))
        history[1] = history[1].format(subdomains.encode_pubkey_entry(bar_bar_sk))

        domain_name = "bar.id"

        empty_zf = """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
"""

        zf_json = zonefile.decode_name_zonefile(domain_name, empty_zf)
        self.assertEqual(zf_json['$origin'], domain_name)

        # bad transition n=0 -> n=0
        sub1 = subdomains.Subdomain("foo", domain_name, subdomains.encode_pubkey_entry(foo_bar_sk), 0, "")

        subdomain_util._extend_with_subdomain(zf_json, sub1)

        history.append(blockstack_zones.make_zone_file(zf_json))

        # bad transition bad sig.
        zf_json = zonefile.decode_name_zonefile(domain_name, empty_zf)
        self.assertEqual(zf_json['$origin'], domain_name)

        sub2 = subdomains.Subdomain("foo", domain_name, subdomains.encode_pubkey_entry(bar_bar_sk), 1, "")
        subdomain_util._extend_with_subdomain(zf_json, sub2)
        history.append(blockstack_zones.make_zone_file(zf_json))

        subdomain_db = subdomains._build_subdomain_db(["bar.id" for x in range(1)], history[:1])
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertNotIn("bar.bar.id", subdomain_db)

        subdomain_db = subdomains._build_subdomain_db(["bar.id" for x in range(2)], history[:2])
        self.assertIn("bar.bar.id", subdomain_db)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 0)

        subdomain_db = subdomains._build_subdomain_db(["bar.id" for x in range(3)], history[:3])
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 0)

        # handle repeated zonefile

        subdomain_db = subdomains._build_subdomain_db(["bar.id" for x in range(3)], history[:3])
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 0)
        subdomains._build_subdomain_db(["bar.id" for x in range(3)], history[:3], subdomain_db = subdomain_db)
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 0)        
def scenario( wallets, **kw ):

    global synchronized

    import blockstack_integration_tests.atlas_network as atlas_network

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

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

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

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

    # register 10 names
    for i in xrange(0, 10):
        res = testlib.blockstack_name_preorder( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr )
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block( **kw )
    
    for i in xrange(0, 10):
        res = testlib.blockstack_name_register( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr )
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block( **kw )

    # start up a simple Atlas test network with two nodes: the main one doing the test, and a subordinate one that treats it as a seed peer.
    network_des = atlas_network.atlas_network_build( [17000], {17000: [16264]}, {}, os.path.join( testlib.working_dir(**kw), "atlas_network" ))
    atlas_network.atlas_network_start( network_des )

    time.sleep(5.0)
    
    # make 10 empty zonefiles and propagate them 
    for i in xrange(0, 10):
        data_pubkey = virtualchain.BitcoinPrivateKey(wallet_keys['data_privkey']).public_key().to_hex()
        empty_zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo_{}.test".format(i), data_pubkey, urls=["file:///tmp/foo_{}.test".format(i)] )
        empty_zonefile_str = blockstack_zones.make_zone_file( empty_zonefile )
        value_hash = blockstack_client.hash_zonefile( empty_zonefile )

        res = testlib.blockstack_name_update( "foo_{}.test".format(i), value_hash, wallets[3].privkey )
        if 'error' in res:
            print json.dumps(res)
            return False

        testlib.next_block( **kw )

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

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

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

    global synchronized, value_hash

    import blockstack_integration_tests.atlas_network as atlas_network

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

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

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

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

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

    # register 10 names
    for i in xrange(0, 10):
        res = testlib.blockstack_name_preorder( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr )
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block( **kw )
    
    for i in xrange(0, 10):
        res = testlib.blockstack_name_register( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr )
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block( **kw )
    
    # make 10 empty zonefiles and propagate them 
    for i in xrange(0, 10):
        data_pubkey = virtualchain.BitcoinPrivateKey(wallet_keys['data_privkey']).public_key().to_hex()
        empty_zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo_{}.test".format(i), data_pubkey, urls=["file:///tmp/foo_{}.test".format(i)] )
        empty_zonefile_str = blockstack_zones.make_zone_file( empty_zonefile )
        value_hash = blockstack_client.hash_zonefile( empty_zonefile )

        res = testlib.blockstack_name_update( "foo_{}.test".format(i), value_hash, wallets[3].privkey )
        if 'error' in res:
            print json.dumps(res)
            return False

        testlib.next_block( **kw )

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

    # start up an atlas network with 16 peers, 8 of which will be active at once.
    # every second, have one peer come online, and one peer go offline.
    # have them all start out knowing about the same seed node.
    atlas_nodes = [17000, 17001, 17002, 17003, 17004, 17005, 17006, 17007, 17008, 17009, 17010, 17011, 17012, 17013, 17014, 17015, 17016]
    atlas_topology = {}
    for i in xrange(0, 9):
        atlas_topology[atlas_nodes[i]] = [16264]

    for i in xrange(9, len(atlas_nodes)):
        atlas_topology[atlas_nodes[i]] = [17008]

    atlas_topology[atlas_nodes[-1]].append( 16264 )
    
    # put the seed after the first four
    all_peers = atlas_nodes[:4] + [16264] + atlas_nodes[4:]

    time_start = int(time.time()) + 60

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

        src_host, src_port = 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)
        offset = now % len(all_peers)
        sample = all_peers + all_peers
        active_range = sample[offset: offset + 8]

        print "Active range: %s, request (%s --> %s)" % (active_range, src_port, dest_port)

        if src_port not in active_range:
            # dead 
            return 1.0

        if dest_port not in active_range:
            # dead
            return 1.0

        return 0.0

    network_des = atlas_network.atlas_network_build( atlas_nodes, atlas_topology, {}, os.path.join( testlib.working_dir(**kw), "atlas_network" ) )
    atlas_network.atlas_network_start( network_des, drop_probability=churn_drop )
        
    print "Waiting 120 seconds for the altas peers to catch up"
    time.sleep(120.0)

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

    global synchronized

    import blockstack_integration_tests.atlas_network as atlas_network

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

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

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

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

    # register 10 names
    for i in xrange(0, 10):
        res = testlib.blockstack_name_preorder("foo_{}.test".format(i),
                                               wallets[2].privkey,
                                               wallets[3].addr)
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block(**kw)

    for i in xrange(0, 10):
        res = testlib.blockstack_name_register("foo_{}.test".format(i),
                                               wallets[2].privkey,
                                               wallets[3].addr)
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block(**kw)

    # start up a simple Atlas test network with two nodes: the main one doing the test, and a subordinate one that treats it as a seed peer.
    network_des = atlas_network.atlas_network_build(
        [17000], {17000: [16264]}, {},
        os.path.join(testlib.working_dir(**kw), "atlas_network"))
    atlas_network.atlas_network_start(network_des)

    time.sleep(5.0)

    # make 10 empty zonefiles and propagate them
    for i in xrange(0, 10):
        data_pubkey = virtualchain.BitcoinPrivateKey(
            wallet_keys['data_privkey']).public_key().to_hex()
        empty_zonefile = blockstack_client.zonefile.make_empty_zonefile(
            "foo_{}.test".format(i),
            data_pubkey,
            urls=["file:///tmp/foo_{}.test".format(i)])
        empty_zonefile_str = blockstack_zones.make_zone_file(empty_zonefile)
        value_hash = blockstack_client.hash_zonefile(empty_zonefile)

        res = testlib.blockstack_name_update("foo_{}.test".format(i),
                                             value_hash, wallets[3].privkey)
        if 'error' in res:
            print json.dumps(res)
            return False

        testlib.next_block(**kw)

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

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

        else:
            time.sleep(1.0)

    # shut down
    atlas_network.atlas_network_stop(network_des)
    return synchronized
    def test_db_builder(self):
        history = [
            """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
foo TXT "owner={}" "seqn=0" "parts=0"
""",
            """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
bar TXT "owner={}" "seqn=0" "parts=0"
""",
]

        foo_bar_sk = keylib.ECPrivateKey()
        bar_bar_sk = keylib.ECPrivateKey()

        history[0] = history[0].format(subdomains.encode_pubkey_entry(foo_bar_sk))
        history[1] = history[1].format(subdomains.encode_pubkey_entry(bar_bar_sk))

        domain_name = "bar.id"

        empty_zf = """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
"""

        zf_json = zonefile.decode_name_zonefile(domain_name, empty_zf)
        self.assertEqual(zf_json['$origin'], domain_name)

        sub1 = subdomains.Subdomain(domain_name, "foo", subdomains.encode_pubkey_entry(foo_bar_sk), 1, "")
        sub2 = subdomains.Subdomain(domain_name, "bar", subdomains.encode_pubkey_entry(bar_bar_sk), 1, "")
        sub1.add_signature(foo_bar_sk)
        sub2.add_signature(bar_bar_sk)

        subdomain_util._extend_with_subdomain(zf_json, sub2)

        history.append(blockstack_zones.make_zone_file(zf_json))

        zf_json = zonefile.decode_name_zonefile(domain_name, empty_zf)
        subdomain_util._extend_with_subdomain(zf_json, sub1)

        history.append(blockstack_zones.make_zone_file(zf_json))

        subdomain_db = subdomains._build_subdomain_db(["bar.id" for x in range(1)], history[:1])
        self.assertIn("foo.bar.id", subdomain_db, "Contents actually: {}".format(subdomain_db.keys()))
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertNotIn("bar.bar.id", subdomain_db)

        subdomain_db = subdomains._build_subdomain_db(["bar.id" for x in range(2)], history[:2])
        self.assertIn("bar.bar.id", subdomain_db)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 0)

        subdomain_db = subdomains._build_subdomain_db(["bar.id" for x in range(3)], history[:3])
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 1)

        subdomain_db = subdomains._build_subdomain_db(["bar.id" for x in range(len(history))], history)
        self.assertEqual(subdomain_db["foo.bar.id"].n, 1)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 1)
示例#45
0
def scenario(wallets, **kw):
    global value_hashes

    virtualchain_dir = os.environ.get('VIRTUALCHAIN_WORKING_DIR', None)
    assert virtualchain_dir

    privkey = keylib.ECPrivateKey(wallets[4].privkey).to_hex()
    config_file = os.path.join(virtualchain_dir, 'snapshots.ini')
    privkey_path = os.path.join(virtualchain_dir, 'snapshots.pkey')
    snapshot_dir = os.path.join(virtualchain_dir, 'snapshots')

    with open(privkey_path, 'w') as f:
        f.write(privkey)

    with open(config_file, 'w') as f:
        f.write("""
[blockstack-snapshots]
private_key = {}
logfile = {}
""".format(privkey_path, os.path.join(virtualchain_dir, 'snapshots.log')))

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

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3)

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

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3)

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

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3)

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

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3)

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

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3)

    zonefile = blockstack_client.zonefile.make_empty_zonefile(
        "foo.test", wallets[0].pubkey_hex)
    zonefile_txt = blockstack_zones.make_zone_file(zonefile)
    zonefile_hash = blockstack_client.storage.get_zonefile_data_hash(
        zonefile_txt)

    value_hashes.append(zonefile_hash)

    assert blockstack_client.storage.put_immutable_data(
        zonefile_txt, '00' * 32, data_hash=zonefile_hash)

    testlib.blockstack_name_update('foo.test', zonefile_hash,
                                   wallets[3].privkey)
    testlib.next_block(**kw)

    # there must be three snapshots
    res = os.listdir(snapshot_dir)
    assert len(res) == 4
    assert 'snapshot.bsk' in res

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 1)

    # now there's only one
    res = os.listdir(snapshot_dir)
    assert len(res) == 2
    assert 'snapshot.bsk' in res

    # restore it
    restore_dir = os.path.join(snapshot_dir, 'test_restore')
    res = restore(os.path.join(snapshot_dir, 'snapshot.bsk'), restore_dir,
                  [wallets[4].pubkey_hex], 1)
    assert res
示例#46
0
    def test_db_builder(self):
        history = [
            """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
foo TXT "owner={}" "seqn=0" "parts=0"
""",
            """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
bar TXT "owner={}" "seqn=0" "parts=0"
""",
        ]

        foo_bar_sk = keylib.ECPrivateKey()
        bar_bar_sk = keylib.ECPrivateKey()

        history[0] = history[0].format(
            subdomains.encode_pubkey_entry(foo_bar_sk))
        history[1] = history[1].format(
            subdomains.encode_pubkey_entry(bar_bar_sk))

        domain_name = "bar.id"

        empty_zf = """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
"""

        zf_json = zonefile.decode_name_zonefile(domain_name, empty_zf)
        self.assertEqual(zf_json['$origin'], domain_name)

        sub1 = subdomains.Subdomain(domain_name, "foo",
                                    subdomains.encode_pubkey_entry(foo_bar_sk),
                                    1, "")
        sub2 = subdomains.Subdomain(domain_name, "bar",
                                    subdomains.encode_pubkey_entry(bar_bar_sk),
                                    1, "")
        sub1.add_signature(foo_bar_sk)
        sub2.add_signature(bar_bar_sk)

        subdomain_util._extend_with_subdomain(zf_json, sub2)

        history.append(blockstack_zones.make_zone_file(zf_json))

        zf_json = zonefile.decode_name_zonefile(domain_name, empty_zf)
        subdomain_util._extend_with_subdomain(zf_json, sub1)

        history.append(blockstack_zones.make_zone_file(zf_json))

        subdomain_db = subdomains._build_subdomain_db(
            ["bar.id" for x in range(1)], history[:1])
        self.assertIn("foo.bar.id", subdomain_db,
                      "Contents actually: {}".format(subdomain_db.keys()))
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertNotIn("bar.bar.id", subdomain_db)

        subdomain_db = subdomains._build_subdomain_db(
            ["bar.id" for x in range(2)], history[:2])
        self.assertIn("bar.bar.id", subdomain_db)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 0)

        subdomain_db = subdomains._build_subdomain_db(
            ["bar.id" for x in range(3)], history[:3])
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 1)

        subdomain_db = subdomains._build_subdomain_db(
            ["bar.id" for x in range(len(history))], history)
        self.assertEqual(subdomain_db["foo.bar.id"].n, 1)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 1)
def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    wallet_keys = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[5].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 )
    
    # migrate profiles 
    res = testlib.migrate_profile( "foo.test", proxy=test_proxy, wallet_keys=wallet_keys )
    if 'error' in res:
        res['test'] = 'Failed to initialize foo.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()
    
    testlib.next_block( **kw )
    
    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None)
    config_dir = os.path.dirname(config_path)
     
    conf = blockstack_client.get_config(config_path)
    assert conf

    api_pass = conf['api_password']

    # make sure we can do REST calls
    res = testlib.blockstack_REST_call('GET', '/v1/blockchains/bitcoin/pending', None, api_pass=api_pass )
    if 'error' in res:
        res['test'] = 'Failed to get queues'
        print json.dumps(res)
        return False

    # make sure we can do REST calls with different app names and user names
    res = testlib.blockstack_REST_call('GET', '/v1/blockchains/bitcoin/pending', None, api_pass=api_pass )
    if 'error' in res:
        res['test'] = 'Failed to get queues'
        print json.dumps(res)
        return False

    # can we even get to the wallet?
    res = testlib.blockstack_REST_call('POST', '/v1/wallet/balance', None, api_pass=api_pass, data={'address': wallets[4].addr, 'amount': 100000} )
    if res['http_status'] != 200:
        res['test'] = 'failed to transfer funds'

    # make zonefile for recipient
    driver_urls = blockstack_client.storage.make_mutable_data_urls('foo.test', use_only=['dht', 'disk'])
    zonefile = blockstack_client.zonefile.make_empty_zonefile('foo.test', wallets[4].pubkey_hex, urls=driver_urls)
    zonefile_txt = blockstack_zones.make_zone_file( zonefile, origin='foo.test', ttl=3600 )

    # register the name bar.test, with min 3 confirmations on its UTXOs
    data = {
        'name': 'bar.test',
        'zonefile': zonefile_txt,
        'owner_address': wallets[4].addr,
        'min_confs': 3
    }

    # should fail
    res = testlib.blockstack_REST_call('POST', '/v1/names', None, api_pass=api_pass, data=data)
    if res['http_status'] == 200:
        res['test'] = 'succeeded in sending bar.test'
        print json.dumps(res)
        error = True
        return False

    # wait for confirmations
    for i in xrange(0, 3):
        testlib.next_block( **kw )

    # should succeed
    res = testlib.blockstack_REST_call('POST', '/v1/names', None, api_pass=api_pass, data=data)
    if 'error' in res or 'error' in res['response']:
        res['test'] = 'failed to send bar.test'
        print json.dumps(res)
        error = True
        return False


    # wait for update to get confirmed 
    for i in xrange(0, 48):
        if i % 12 == 0:
            print "waiting for RPC daemon to catch up"
            time.sleep(10)

        testlib.next_block( **kw )

    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test", None, api_pass=api_pass)
    if 'error' in res:
        res['test'] = 'Failed to query name'
        print json.dumps(res)
        error = True
        return False

    if res['http_status'] != 200:
        res['test'] = 'HTTP status {}, response = {}'.format(res['http_status'], res['response'])
        print json.dumps(res)
        error = True
        return False

    # should now be registered 
    if res['response']['status'] != 'registered':
        print "register not complete"
        print json.dumps(res)
        return False
示例#48
0
    def test_db_builder_bad_transitions(self):
        history = [
            """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
foo TXT "owner={}" "seqn=0" "parts=0"
""",
            """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
bar TXT "owner={}" "seqn=0" "parts=0"
""",
        ]

        foo_bar_sk = keylib.ECPrivateKey()
        bar_bar_sk = keylib.ECPrivateKey()

        history[0] = history[0].format(
            subdomains.encode_pubkey_entry(foo_bar_sk))
        history[1] = history[1].format(
            subdomains.encode_pubkey_entry(bar_bar_sk))

        domain_name = "bar.id"

        empty_zf = """$ORIGIN bar.id
$TTL 3600
pubkey TXT "pubkey:data:0"
registrar URI 10 1 "bsreg://foo.com:8234"
"""

        zf_json = zonefile.decode_name_zonefile(domain_name, empty_zf)
        self.assertEqual(zf_json['$origin'], domain_name)

        # bad transition n=0 -> n=0
        sub1 = subdomains.Subdomain("foo", domain_name,
                                    subdomains.encode_pubkey_entry(foo_bar_sk),
                                    0, "")

        subdomain_util._extend_with_subdomain(zf_json, sub1)

        history.append(blockstack_zones.make_zone_file(zf_json))

        # bad transition bad sig.
        zf_json = zonefile.decode_name_zonefile(domain_name, empty_zf)
        self.assertEqual(zf_json['$origin'], domain_name)

        sub2 = subdomains.Subdomain("foo", domain_name,
                                    subdomains.encode_pubkey_entry(bar_bar_sk),
                                    1, "")
        subdomain_util._extend_with_subdomain(zf_json, sub2)
        history.append(blockstack_zones.make_zone_file(zf_json))

        subdomain_db = subdomains._build_subdomain_db(
            ["bar.id" for x in range(1)], history[:1])
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertNotIn("bar.bar.id", subdomain_db)

        subdomain_db = subdomains._build_subdomain_db(
            ["bar.id" for x in range(2)], history[:2])
        self.assertIn("bar.bar.id", subdomain_db)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 0)

        subdomain_db = subdomains._build_subdomain_db(
            ["bar.id" for x in range(3)], history[:3])
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 0)

        # handle repeated zonefile

        subdomain_db = subdomains._build_subdomain_db(
            ["bar.id" for x in range(3)], history[:3])
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 0)
        subdomains._build_subdomain_db(["bar.id" for x in range(3)],
                                       history[:3],
                                       subdomain_db=subdomain_db)
        self.assertEqual(subdomain_db["foo.bar.id"].n, 0)
        self.assertEqual(subdomain_db["bar.bar.id"].n, 0)
def scenario(wallets, **kw):

    global synchronized, value_hash

    import blockstack_integration_tests.atlas_network as atlas_network

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

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

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

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

    # register 10 names
    for i in xrange(0, 10):
        res = testlib.blockstack_name_preorder("foo_{}.test".format(i),
                                               wallets[2].privkey,
                                               wallets[3].addr)
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block(**kw)

    for i in xrange(0, 10):
        res = testlib.blockstack_name_register("foo_{}.test".format(i),
                                               wallets[2].privkey,
                                               wallets[3].addr)
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block(**kw)

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

    atlas_topology[17000] = [16264, 17001]
    atlas_topology[17007] = [17006]

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

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

        src_host, src_port = blockstack_client.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 10 empty zonefiles and propagate them
    for i in xrange(0, 10):
        data_pubkey = virtualchain.BitcoinPrivateKey(
            wallet_keys['data_privkey']).public_key().to_hex()
        empty_zonefile = blockstack_client.zonefile.make_empty_zonefile(
            "foo_{}.test".format(i),
            data_pubkey,
            urls=["file:///tmp/foo_{}.test".format(i)])
        empty_zonefile_str = blockstack_zones.make_zone_file(empty_zonefile)
        value_hash = blockstack_client.hash_zonefile(empty_zonefile)

        res = testlib.blockstack_name_update("foo_{}.test".format(i),
                                             value_hash, wallets[3].privkey)
        if 'error' in res:
            print json.dumps(res)
            return False

        testlib.next_block(**kw)

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

    # wait at most 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 value_hashes, namespace_ids

    virtualchain_dir = kw['working_dir']
    assert virtualchain_dir

    privkey = keylib.ECPrivateKey(wallets[4].privkey).to_hex()
    config_file = os.path.join(virtualchain_dir, 'snapshots.ini')
    privkey_path = os.path.join(virtualchain_dir, 'snapshots.pkey')
    snapshot_dir = os.path.join(virtualchain_dir, 'snapshots')

    with open(privkey_path, 'w') as f:
        f.write(privkey)

    with open(config_file, 'w') as f:
        f.write("""
[blockstack-snapshots]
private_key = {}
logfile = {}
""".format(privkey_path, os.path.join(virtualchain_dir, 'snapshots.log')))

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

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3)

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

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3)

    zonefile = blockstack_client.zonefile.make_empty_zonefile(
        "foo.test", wallets[0].pubkey_hex)
    zonefile_txt = blockstack_zones.make_zone_file(zonefile)
    zonefile_hash = blockstack_client.storage.get_zonefile_data_hash(
        zonefile_txt)

    value_hashes.append(zonefile_hash)

    namespace_ids.append('test')

    resp = testlib.blockstack_name_import("imported.test", wallets[3].addr,
                                          zonefile_hash, wallets[1].privkey)
    if 'error' in resp:
        print json.dumps(resp, indent=4)
        return False

    testlib.next_block(**kw)

    # store zonefile
    res = testlib.blockstack_put_zonefile(zonefile_txt)
    assert res

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3)

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

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3)

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

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3)

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

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 3)

    zonefile = blockstack_client.zonefile.make_empty_zonefile(
        "foo.test", wallets[0].pubkey_hex)
    zonefile_txt = blockstack_zones.make_zone_file(zonefile)
    zonefile_hash = blockstack_client.storage.get_zonefile_data_hash(
        zonefile_txt)

    value_hashes.append(zonefile_hash)

    testlib.blockstack_name_update('foo.test', zonefile_hash,
                                   wallets[3].privkey)
    testlib.next_block(**kw)

    time.sleep(1.0)

    # store zonefile
    res = testlib.blockstack_put_zonefile(zonefile_txt)
    assert res

    # there must be three snapshots
    res = os.listdir(snapshot_dir)
    assert len(res) == 4
    assert 'snapshot.bsk' in res

    assert take_snapshot(config_file, virtualchain_dir, snapshot_dir, 1)

    # now there's only one
    res = os.listdir(snapshot_dir)
    assert len(res) == 2
    assert 'snapshot.bsk' in res

    # restore it
    restore_dir = os.path.join(snapshot_dir, 'test_restore')
    res = restore(virtualchain_dir, os.path.join(snapshot_dir, 'snapshot.bsk'),
                  restore_dir, [wallets[4].pubkey_hex], 1)
    assert res
示例#51
0
def scenario(wallets, **kw):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    wallet_keys = testlib.blockstack_client_initialize_wallet(
        "0123456789abcdef", wallets[5].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)

    for i in xrange(0, 3):
        testlib.next_block(**kw)

    # try to preorder another namespace; it should fail
    res = testlib.blockstack_namespace_preorder("test2", wallets[1].addr,
                                                wallets[0].privkey)
    if 'error' not in res:
        print 'accidentally succeeded to preorder test2'
        return False

    # try to reveal; it should fail
    res = 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)
    if 'error' not in res:
        print 'accidentally succeeded to reveal test'
        return False

    testlib.expect_snv_fail_at("test2", testlib.get_current_block(**kw) + 1)
    testlib.expect_snv_fail_at("test", testlib.get_current_block(**kw) + 1)

    for i in xrange(0, 3):
        testlib.next_block(**kw)

    # should succeed
    res = 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)
    if 'error' in res:
        print res
        return False

    for i in xrange(0, 3):
        testlib.next_block(**kw)

    # should fail, since we have an unusable address
    res = testlib.blockstack_namespace_ready("test", wallets[1].privkey)
    if 'error' not in res:
        print res
        return False

    testlib.expect_snv_fail_at("test", testlib.get_current_block(**kw) + 1)

    for i in xrange(0, 3):
        testlib.next_block(**kw)

    # should work now
    res = testlib.blockstack_namespace_ready("test", wallets[1].privkey)
    if 'error' in res:
        print res
        return False

    testlib.next_block(**kw)

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

    for i in xrange(0, 3):
        testlib.next_block(**kw)

    # should fail to re-preorder, since address isn't ready
    res = testlib.blockstack_name_preorder("foo2.test", wallets[2].privkey,
                                           wallets[3].addr)
    if 'error' not in res:
        print 'accidentally succeeded to preorder foo2.test'
        return False

    testlib.expect_snv_fail_at("foo2.test",
                               testlib.get_current_block(**kw) + 1)

    # should fail for the same reason: the payment address is not ready
    res = testlib.blockstack_name_register("foo.test", wallets[2].privkey,
                                           wallets[3].addr)
    if 'error' not in res:
        print 'accidentally succeeded to register foo.test'
        return False

    testlib.expect_snv_fail_at("foo.test", testlib.get_current_block(**kw) + 1)

    for i in xrange(0, 3):
        testlib.next_block(**kw)

    # should succeed now that it's confirmed
    res = testlib.blockstack_name_register("foo.test", wallets[2].privkey,
                                           wallets[3].addr)
    if 'error' in res:
        print res
        return False

    for i in xrange(0, 3):
        testlib.next_block(**kw)

    # should fail; address not ready
    res = testlib.migrate_profile("foo.test",
                                  proxy=test_proxy,
                                  wallet_keys=wallet_keys)
    if 'error' not in res:
        print 'accidentally succeeded to migrate profile'
        return False

    testlib.expect_snv_fail_at("foo.test", testlib.get_current_block(**kw) + 1)

    for i in xrange(0, 3):
        testlib.next_block(**kw)

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

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

    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None)

    # make a session
    datastore_pk = keylib.ECPrivateKey(wallets[-1].privkey).to_hex()
    res = testlib.blockstack_cli_app_signin(
        "foo.test", datastore_pk, 'register.app', [
            'names', 'register', 'prices', 'zonefiles', 'blockchain',
            'node_read', 'wallet_read'
        ])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return

    ses = res['token']

    # make zonefile for recipient
    driver_urls = blockstack_client.storage.make_mutable_data_urls(
        'bar.test', use_only=['dht', 'disk'])
    zonefile = blockstack_client.zonefile.make_empty_zonefile(
        'bar.test', wallets[4].pubkey_hex, urls=driver_urls)
    zonefile_txt = blockstack_zones.make_zone_file(zonefile,
                                                   origin='bar.test',
                                                   ttl=3600)

    # register the name bar.test (no zero-conf, should fail)
    res = testlib.blockstack_REST_call('POST',
                                       '/v1/names',
                                       ses,
                                       data={
                                           'name': 'bar.test',
                                           'zonefile': zonefile_txt,
                                           'owner_address': wallets[4].addr
                                       })
    if res['http_status'] == 200:
        print 'accidentally succeeded to register bar.test'
        print res
        return False

    # let's test /v1/wallet/balance
    res = testlib.blockstack_REST_call('GET', '/v1/wallet/balance', ses)
    if res['http_status'] != 200:
        print '/v1/wallet/balance returned ERR'
        print json.dumps(res)
        return False
    if res['response']['balance']['satoshis'] > 0:
        print '/v1/wallet/balance accidentally incorporated 0-conf txns in balance register bar.test'
        print json.dumps(res['response'])
        return False

    # let's test /v1/wallet/balance with minconfs=0
    res = testlib.blockstack_REST_call('GET', '/v1/wallet/balance/0', ses)
    if res['http_status'] != 200:
        print '/v1/wallet/balance/0 returned ERR'
        print json.dumps(res)
        return False
    if res['response']['balance']['satoshis'] < 1e6:
        print "/v1/wallet/balance/0 didn't incorporate 0-conf txns"
        print json.dumps(res['response'])
        return False

    # register the name bar.test (1-conf, should fail)
    res = testlib.blockstack_REST_call('POST',
                                       '/v1/names',
                                       ses,
                                       data={
                                           'name': 'bar.test',
                                           'zonefile': zonefile_txt,
                                           'owner_address': wallets[4].addr,
                                           'min_confs': 1
                                       })
    if res['http_status'] == 200:
        print 'accidentally succeeded to register bar.test'
        print res
        return False

    # register the name bar.test (zero-conf, should succeed)
    res = testlib.blockstack_REST_call('POST',
                                       '/v1/names',
                                       ses,
                                       data={
                                           'name': 'bar.test',
                                           'zonefile': zonefile_txt,
                                           'owner_address': wallets[4].addr,
                                           'min_confs': 0
                                       })
    if 'error' in res:
        res['test'] = 'Failed to register user'
        print json.dumps(res)
        error = True
        return False

    print res
    tx_hash = res['response']['transaction_hash']

    # wait for preorder to get confirmed...
    for i in xrange(0, 6):
        testlib.next_block(**kw)

    res = testlib.verify_in_queue(ses, 'bar.test', 'preorder', tx_hash)
    if not res:
        return False

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

    # wait for register to go through
    print 'Wait for register to be submitted'
    time.sleep(10)

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

    res = testlib.verify_in_queue(ses, 'bar.test', 'register', None)
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block(**kw)

    print 'Wait for update to be submitted'
    time.sleep(10)

    # wait for update to get confirmed
    for i in xrange(0, 6):
        testlib.next_block(**kw)

    res = testlib.verify_in_queue(ses, 'bar.test', 'update', None)
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block(**kw)

    print 'Wait for transfer to be submitted'
    time.sleep(10)

    # wait for transfer to get confirmed
    for i in xrange(0, 6):
        testlib.next_block(**kw)

    res = testlib.verify_in_queue(ses, 'bar.test', 'transfer', None)
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block(**kw)

    print 'Wait for transfer to be confirmed'
    time.sleep(10)

    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test", ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    zonefile_hash = res['response']['zonefile_hash']

    # should still be registered
    if res['response']['status'] != 'registered':
        print "register not complete"
        print json.dumps(res)
        return False

    # do we have the history for the name?
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/history",
                                       ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = "Failed to get name history for foo.test"
        print json.dumps(res)
        return False

    # valid history?
    hist = res['response']
    if len(hist.keys()) != 4:
        res['test'] = 'Failed to get update history'
        res['history'] = hist
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    # get the zonefile
    res = testlib.blockstack_REST_call(
        "GET", "/v1/names/bar.test/zonefile/{}".format(zonefile_hash), ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name zonefile'
        print json.dumps(res)
        return False

    # same zonefile we put?
    if res['response']['zonefile'] != zonefile_txt:
        res['test'] = 'mismatched zonefile, expected\n{}\n'.format(
            zonefile_txt)
        print json.dumps(res)
        return False
def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    wallet_keys = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[5].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 )
    
    # migrate profiles 
    res = testlib.migrate_profile( "foo.test", proxy=test_proxy, wallet_keys=wallet_keys )
    if 'error' in res:
        res['test'] = 'Failed to initialize foo.test profile'
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

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

    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None)

    # make a session 
    datastore_pk = keylib.ECPrivateKey(wallets[-1].privkey).to_hex()
    res = testlib.blockstack_cli_app_signin("foo.test", datastore_pk, 'register.app', ['names', 'register', 'prices', 'zonefiles', 'blockchain', 'node_read'])
    if 'error' in res:
        print json.dumps(res, indent=4, sort_keys=True)
        error = True
        return 

    ses = res['token']

    # for funsies, get the price of .test
    res = testlib.blockstack_REST_call('GET', '/v1/prices/namespaces/test', ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get price of .test'
        print json.dumps(res)
        return False

    test_price = res['response']['satoshis']
    print '\n\n.test costed {} satoshis\n\n'.format(test_price)

    # get the price for bar.test
    res = testlib.blockstack_REST_call('GET', '/v1/prices/names/bar.test', ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get price of bar.test'
        print json.dumps(res)
        return False

    bar_price = res['response']['total_estimated_cost']['satoshis']
    print "\n\nbar.test will cost {} satoshis\n\n".format(bar_price)
  
    # make zonefile for recipient
    driver_urls = blockstack_client.storage.make_mutable_data_urls('bar.test', use_only=['dht', 'disk'])
    zonefile = blockstack_client.zonefile.make_empty_zonefile('bar.test', wallets[4].pubkey_hex, urls=driver_urls)
    zonefile_txt = blockstack_zones.make_zone_file( zonefile, origin='bar.test', ttl=3600 )

    # register the name bar.test 
    res = testlib.blockstack_REST_call('POST', '/v1/names', ses, data={'name': 'bar.test', 'zonefile': zonefile_txt, 'owner_address': wallets[4].addr})
    if 'error' in res:
        res['test'] = 'Failed to register user'
        print json.dumps(res)
        error = True
        return False

    print res
    tx_hash = res['response']['transaction_hash']

    # wait for preorder to get confirmed...
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'preorder', tx_hash )
    if not res:
        return False

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

    # wait for register to go through 
    print 'Wait for register to be submitted'
    time.sleep(10)

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

    res = testlib.verify_in_queue(ses, 'bar.test', 'register', None )
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )

    print 'Wait for update to be submitted'
    time.sleep(10)

    # wait for update to get confirmed 
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'update', None )
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )
  
    print 'Wait for transfer to be submitted'
    time.sleep(10)

    # wait for transfer to get confirmed 
    for i in xrange(0, 6):
        testlib.next_block( **kw )

    res = testlib.verify_in_queue(ses, 'bar.test', 'transfer', None )
    if not res:
        return False

    for i in xrange(0, 6):
        testlib.next_block( **kw )
  
    print 'Wait for transfer to be confirmed'
    time.sleep(10)

    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test", ses)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    zonefile_hash = res['response']['zonefile_hash']

    # should still be registered 
    if res['response']['status'] != 'registered':
        print "register not complete"
        print json.dumps(res)
        return False

    # do we have the history for the name?
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/history", ses )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = "Failed to get name history for foo.test"
        print json.dumps(res)
        return False

    # valid history?
    hist = res['response']
    if len(hist.keys()) != 4:
        res['test'] = 'Failed to get update history'
        res['history'] = hist
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    # get the zonefile
    res = testlib.blockstack_REST_call("GET", "/v1/names/bar.test/zonefile/{}".format(zonefile_hash), ses )
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name zonefile'
        print json.dumps(res)
        return False

    # same zonefile we put?
    if res['response']['zonefile'] != zonefile_txt:
        res['test'] = 'mismatched zonefile, expected\n{}\n'.format(zonefile_txt)
        print json.dumps(res)
        return False
def scenario( wallets, **kw ):

    global synchronized, value_hash

    import blockstack_integration_tests.atlas_network as atlas_network

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

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

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

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

    # register 10 names
    for i in xrange(0, 10):
        res = testlib.blockstack_name_preorder( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr )
        if 'error' in res:
            print json.dumps(res)
            return False

    testlib.next_block( **kw )
    
    for i in xrange(0, 10):
        res = testlib.blockstack_name_register( "foo_{}.test".format(i), wallets[2].privkey, wallets[3].addr )
        if 'error' in res:
            print json.dumps(res)
            return False

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

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

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

        src_host, src_port = blockstack_client.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 10 empty zonefiles and propagate them 
    for i in xrange(0, 10):
        data_pubkey = virtualchain.BitcoinPrivateKey(wallet_keys['data_privkey']).public_key().to_hex()
        empty_zonefile = blockstack_client.zonefile.make_empty_zonefile( "foo_{}.test".format(i), data_pubkey, urls=["file:///tmp/foo_{}.test".format(i)] )
        empty_zonefile_str = blockstack_zones.make_zone_file( empty_zonefile )
        value_hash = blockstack_client.hash_zonefile( empty_zonefile )

        res = testlib.blockstack_name_update( "foo_{}.test".format(i), value_hash, wallets[3].privkey )
        if 'error' in res:
            print json.dumps(res)
            return False

        testlib.next_block( **kw )

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

    # wait at most 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

    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)
    
    # store a new zonefile
    data_pubkey = wallet['data_pubkey']
    zonefile = blockstack_client.user.make_empty_user_zonefile( "foo.test", data_pubkey )
    assert blockstack_client.user.put_immutable_data_zonefile( zonefile, "testdata", blockstack_client.get_data_hash("testdata") )

    zonefile_txt = blockstack_zones.make_zone_file( zonefile )
    zonefile_hash = blockstack_client.storage.get_zonefile_data_hash( zonefile_txt )
   
    print >> sys.stderr, "\n\nzonefile hash: %s\nzonefile:\n%s\n\n" % (zonefile_hash, zonefile_txt)

    # will store to queue
    test_proxy = testlib.make_proxy()
    config_path = test_proxy.config_path
    conf = blockstack_client.config.get_config(config_path)
    queuedb_path = conf['queue_path']

    # update the zonefile hash, but not the zonefile.
    resp = testlib.blockstack_cli_set_zonefile_hash( "foo.test", zonefile_hash )
    if 'error' in resp:
        print >> sys.stderr, "\nFailed to set zonefile hash: %s\n" % resp
        return False

    txhash = resp['transaction_hash']
    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)

    # stop endpoint
    print >> sys.stderr, "\nstopping RPC daemon\n"
    config_dir = os.path.dirname(test_proxy.config_path)

    blockstack_client.rpc.local_rpc_stop(config_dir=config_dir)
    time.sleep(3)

    # store to queue
    res = blockstack_client.backend.queue.queue_append("update", "foo.test", txhash, payment_address=wallets[2].addr, owner_address=wallets[3].addr,
                                                       config_path=test_proxy.config_path, zonefile_data=zonefile_txt, zonefile_hash=zonefile_hash, path=queuedb_path )

    # verify that we can sync the zonefile, using the in-queue zonefile
    resp = testlib.blockstack_cli_sync_zonefile( "foo.test" )
    if 'error' in resp:
        print >> sys.stderr, "\nfailed to sync zonefile: %s\n" % resp
        return False

    blockstack_client.backend.queue.queuedb_remove("update", "foo.test", txhash, path=queuedb_path )

    print >> sys.stderr, "\nstarting RPC daemon\n"
    blockstack_client.actions.start_rpc_endpoint(config_dir, password="******")
    time.sleep(3)

    # store a new zonefile
    zonefile = blockstack_client.user.make_empty_user_zonefile( "foo.test", data_pubkey )
    blockstack_client.user.put_immutable_data_zonefile( zonefile, "testdata2", blockstack_client.get_data_hash("testdata") )

    zonefile_txt = blockstack_zones.make_zone_file( zonefile )
    zonefile_hash = blockstack_client.storage.get_zonefile_data_hash( zonefile_txt )

    # store locally 
    res = blockstack_client.profile.store_name_zonefile("foo.test", zonefile, None, storage_drivers=['disk'])
    if 'error' in res:
        print >> sys.stderr, "\nFailed to store zonefile: %s\n" % res
        return False

    # update the zonefile hash, but not the zonefile.
    resp = testlib.blockstack_cli_set_zonefile_hash( "foo.test", zonefile_hash )
    if 'error' in resp:
        print >> sys.stderr, "\nFailed to set zonefile hash: %s\n" % resp
        return False

    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 )

    # verify that we can sync the zonefile, using the on-disk zonefile
    resp = testlib.blockstack_cli_sync_zonefile( "foo.test" )
    
    if 'error' in resp:
        print >> sys.stderr, "update error: %s" % resp['error']
        return False
    
    # wait for it to go through 
    for i in xrange(0, 12):
        testlib.next_block( **kw )

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