コード例 #1
0
ファイル: scripts.py プロジェクト: nokiam9/blockstack-core
def get_public_key_hex_from_tx(inputs, address):
    """
    Given a list of inputs and the address of one of the inputs,
    find the public key.

    This only works for p2pkh scripts.

    We only really need this for NAMESPACE_REVEAL, but we included 
    it in other transactions' consensus data for legacy reasons that
    now have to be supported forever :(
    """

    ret = None
    for inp in inputs:
        input_scriptsig = inp['script']
        input_script_code = virtualchain.btc_script_deserialize(
            input_scriptsig)
        if len(input_script_code) == 2:
            # signature pubkey
            pubkey_candidate = input_script_code[1]
            pubkey = None
            try:
                pubkey = virtualchain.BitcoinPublicKey(pubkey_candidate)
            except Exception as e:
                traceback.print_exc()
                log.warn("Invalid public key {}".format(pubkey_candidate))
                continue

            if address != pubkey.address():
                continue

            # success!
            return pubkey_candidate

    return None
コード例 #2
0
def get_wallet_addr( wallet ):
    """
    Get a wallet's address
    """
    if type(wallet.privkey) in [str, unicode]:
        return virtualchain.BitcoinPublicKey(wallet.pubkey_hex).address()
    else:
        return wallet.addr
コード例 #3
0
ファイル: scripts.py プロジェクト: zhilinwww/blockstack-core
def get_public_key_hex_from_tx( inputs, address ):
    """
    Given a list of inputs and the address of one of the inputs,
    find the public key.

    This only works for p2pkh scripts.

    We only really need this for NAMESPACE_REVEAL, but we included 
    it in other transactions' consensus data for legacy reasons that
    now have to be supported forever :(
    """
    
    ret = None 
    
    for inp in inputs:
        
        input_scriptsig = inp.get('scriptSig', None )
        if input_scriptsig is None:
            continue 
        
        input_asm = input_scriptsig.get("asm")
        
        if len(input_asm.split(" ")) >= 2:
            
            # public key is the second hex string.  verify it matches the address
            pubkey_hex = input_asm.split(" ")[1]
            pubkey = None 
            
            try:
                pubkey = virtualchain.BitcoinPublicKey( str(pubkey_hex) ) 
            except Exception, e: 
                traceback.print_exc()
                log.warning("Invalid public key '%s'" % pubkey_hex)
                continue 
            
            if address != pubkey.address():
                continue 
            
            ret = pubkey_hex
            break
コード例 #4
0
def fill_wallet(bitcoind, wallet, value):
    """
    Fill a test wallet on regtet bitcoind

    Return True on success
    Raise an error
    """
    if type(wallet.privkey) in [str, unicode]:
        #single private key
        testnet_wif = wallet.privkey
        if not testnet_wif.startswith("c"):
            testnet_wif = virtualchain.BitcoinPrivateKey(testnet_wif).to_wif()

        bitcoind.importprivkey(testnet_wif, "")

        addr = virtualchain.BitcoinPublicKey(wallet.pubkey_hex).address()
        log.info("Fill %s with %s " % (addr, value))
        bitcoind.sendtoaddress(addr, value)

    else:
        # multisig address
        testnet_wifs = []
        testnet_pubks = []
        for pk in wallet.privkey['private_keys']:
            if not pk.startswith("c"):
                pk = virtualchain.BitcoinPrivateKey(pk).to_wif()

            testnet_wifs.append(pk)
            testnet_pubks.append(
                virtualchain.BitcoinPrivateKey(pk).public_key().to_hex())

        multisig_info = virtualchain.make_multisig_info(wallet.m, testnet_wifs)
        bitcoind.addmultisigaddress(wallet.m, testnet_pubks)
        bitcoind.importaddress(multisig_info['address'])

        log.debug("Fill %s with %s" % (multisig_info['address'], value))
        bitcoind.sendtoaddress(multisig_info['address'], value)
    return True
コード例 #5
0
def get_public_key_hex_from_tx( inputs, address ):
    """
    Given a list of inputs and the address of one of the inputs,
    find the public key.

    This only works for p2pkh scripts.
    """
    
    ret = None 
    
    for inp in inputs:
        
        input_scriptsig = inp.get('scriptSig', None )
        if input_scriptsig is None:
            continue 
        
        input_asm = input_scriptsig.get("asm")
        
        if len(input_asm.split(" ")) >= 2:
            
            # public key is the second hex string.  verify it matches the address
            pubkey_hex = input_asm.split(" ")[1]
            pubkey = None 
            
            try:
                pubkey = virtualchain.BitcoinPublicKey( str(pubkey_hex) ) 
            except Exception, e: 
                traceback.print_exc()
                log.warning("Invalid public key '%s'" % pubkey_hex)
                continue 
            
            if address != pubkey.address():
                continue 
            
            ret = pubkey_hex
            break
コード例 #6
0
def get_name_profile(name,
                     zonefile_storage_drivers=None,
                     profile_storage_drivers=None,
                     create_if_absent=False,
                     proxy=None,
                     user_zonefile=None,
                     name_record=None,
                     include_name_record=False,
                     include_raw_zonefile=False,
                     use_zonefile_urls=True,
                     decode_profile=True):
    """
    Given the name of the user, look up the user's record hash,
    and then get the record itself from storage.

    If the user's zonefile is really a legacy profile, then 
    the profile will be the converted legacy profile.  The
    returned zonefile will still be a legacy profile, however.
    The caller can check this and perform the conversion automatically.

    Returns (profile, zonefile) on success.  If include_name_record is True, then zonefile['name_record'] will be defined and will contain the user's blockchain information
    Returns (None, {'error': ...}) on failure
    """

    if proxy is None:
        proxy = get_default_proxy()

    raw_zonefile = None

    if user_zonefile is None:
        user_zonefile = get_name_zonefile(
            name,
            create_if_absent=create_if_absent,
            proxy=proxy,
            name_record=name_record,
            include_name_record=True,
            storage_drivers=zonefile_storage_drivers,
            include_raw_zonefile=include_raw_zonefile)
        if user_zonefile is None:
            return (None, {'error': 'No user zonefile'})

        if 'error' in user_zonefile:
            return (None, user_zonefile)

        name_record = user_zonefile['name_record']
        del user_zonefile['name_record']

        raw_zonefile = None
        if include_raw_zonefile:
            raw_zonefile = user_zonefile['raw_zonefile']
            del user_zonefile['raw_zonefile']

        user_zonefile = user_zonefile['zonefile']

    # is this really a legacy profile?
    if blockstack_profiles.is_profile_in_legacy_format(user_zonefile):
        # convert it
        log.debug("Converting legacy profile to modern profile")
        user_profile = blockstack_profiles.get_person_from_legacy_format(
            user_zonefile)

    elif not user_db.is_user_zonefile(user_zonefile):
        # not a legacy profile, but a custom profile
        log.debug("Using custom legacy profile")
        user_profile = copy.deepcopy(user_zonefile)

    else:
        # get user's data public key
        user_address = None
        old_address = None

        try:
            user_data_pubkey = user_db.user_zonefile_data_pubkey(user_zonefile)
            if user_data_pubkey is not None:
                user_data_pubkey = str(user_data_pubkey)
                user_address = virtualchain.BitcoinPublicKey(
                    user_data_pubkey).address()

        except ValueError:
            # user decided to put multiple keys under the same name into the zonefile.
            # so don't use them.
            user_data_pubkey = None

        # convert to address
        if name_record is None:
            name_record = proxy.get_name_blockchain_record(name)
            if name_record is None or 'error' in name_record:
                log.error("Failed to look up name record for '%s'" % name)
                return (None, {'error': 'Failed to look up name record'})

        old_address = name_record['address']
        if user_address is None:
            # cut to the chase
            user_address = old_address

        user_profile = load_name_profile(
            name,
            user_zonefile,
            user_address,
            old_address,
            use_zonefile_urls=use_zonefile_urls,
            storage_drivers=profile_storage_drivers,
            decode=decode_profile)

        if user_profile is not None:
            if decode_profile:
                assert isinstance(user_profile, dict)
            else:
                assert type(user_profile) in [str, unicode]

        else:
            log.debug("WARN: no user profile for %s" % name)
            if create_if_absent:
                user_profile = user_db.make_empty_user_profile()
            else:
                return (None, {'error': 'Failed to load user profile'})

    # finally, if the caller asked for the name record, and we didn't get a chance to look it up,
    # then go get it.
    if include_name_record:
        if name_record is None:
            name_record = proxy.get_name_blockchain_record(name)
            if name_record is None or 'error' in name_record:
                log.error("Failed to look up name record for '%s'" % name)
                return (None, {'error': 'Failed to look up name record'})

        user_zonefile['name_record'] = name_record

    if include_raw_zonefile:
        if raw_zonefile is not None:
            user_zonefile['raw_zonefile'] = raw_zonefile

    return (user_profile, user_zonefile)
コード例 #7
0
def parse_nameop( opcode, payload, fake_pubkey, recipient=None, recipient_address=None, import_update_hash=None, burn_address=None, reveal_address=None ):

    opcode_name = OPCODE_NAMES[opcode]
    pubk = virtualchain.BitcoinPublicKey(fake_pubkey)
    address = pubk.address()
    script_pubkey = virtualchain.make_payment_script( address )
    senders = [{
        "script_pubkey": script_pubkey,
        "script_type": "pubkeyhash",
        "addresses": [ address ]
    }]

    # just enough to get the public key
    inputs = [{
        'script': 'ignored {}'.format(fake_pubkey).encode('hex')
    }]

    script = "OP_RETURN %s" % payload

    try:
        scripthex = virtualchain.make_data_script(binascii.hexlify(payload))
    except:
        if len(payload) == 0:
            scripthex = "6a"
        else:
            print 'failed on {}'.format(payload)
            raise

    outputs = [{
        'script': scripthex,
        'value': 0
    }]

    if recipient_address is not None:
        script = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % binascii.hexlify( virtualchain.lib.hashing.bin_double_sha256( fake_pubkey ) )
        scripthex = virtualchain.make_payment_script( recipient_address )
        outputs.append( {
            'script': scripthex,
            "value": 10000000
        })

    if import_update_hash is not None:
        script = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % import_update_hash
        scripthex = virtualchain.make_payment_script( virtualchain.hex_hash160_to_address( import_update_hash ) )
        outputs.append( {
            "script": scripthex,
            "value": 10000000
        })

    elif burn_address is not None:
        scripthex = virtualchain.make_payment_script( burn_address )
        outputs.append( {
            "script": scripthex,
            "value": 10000000
        })
    
    elif reveal_address is not None:
        scripthex = virtualchain.make_payment_script( reveal_address )
        outputs.append( {
            "script": scripthex,
            "value": 10000000
        })

    try:
        op = op_extract( opcode_name, payload, senders, inputs, outputs, 488501, 0, "00" * 64 )  
    except AssertionError, ae:
        # failed to parse
        return None
コード例 #8
0
def run_zonefilemanage():


    working_dir = "/tmp/zonefilemanage"

    # errase prior state
    if os.path.exists(working_dir):
        log.debug("Remove %s " % working_dir)
        shutil.rmtree(working_dir)


    if not os.path.exists(working_dir):
        os.makedirs(working_dir)

    # export to test
    os.environ["VIRTUALCHAIN_WORKING_DIR"] = working_dir

    # set up bitcoind
    bitcoind_regtest_reset()

    virtualchain_working_dir = os.environ["VIRTUALCHAIN_WORKING_DIR"]

    spv_header_path = os.path.join(virtualchain_working_dir, "spv_headers.dat")
    virtualchain.setup_virtualchain(state_engine)

    # db = state_engine.get_db_state(disposition=state_engine.DISPOSITION_RW)

    log.info("Connect to the bitcoind ")

    # Start the pinger
    pinger = Pinger()
    pinger.start()

    bitcoind = bitcoin_regtest_connect(bitcoin_regtest_opts())

    if is_main_worker():
        log.info("fill up the default wallet")
        # set up the default payment wallet
        default_payment_wallet = MultisigWallet(2, '5JYAj69z2GuFAZHrkhRuBKoCmKh6GcPXgcw9pbH8e8J2pu2RU9z',
                                                        '5Kfg4xkZ1gGN5ozgDZ37Mn3EH9pXSuWZnQt1pzax4cLax8PetNs',
                                                        '5JXB7rNxZa8yQtpuKtwy1nWUUTgdDEYTDmaEqQvKKC8HCWs64bL')

        # load wallets
        bitcoion_regtest_fill_wallets(wallets, default_payment_wallet=default_payment_wallet)

    else:
        # Watch out for wallets
        for wallet in wallets:

            testnet_wif = wallet.privkey
            if not testnet_wif.startswith("c"):
                testnet_wif = virtualchain.BitcoinPrivateKey(testnet_wif).to_wif()

            bitcoind.importprivkey(testnet_wif, "")

            addr = virtualchain.BitcoinPublicKey(wallet.pubkey_hex).address()
            log.info("Watch out for %s" % (addr))

        for wallet in wallets:
            addr = get_wallet_addr(wallet)
            unspents = bitcoind.listunspent(0, 200000, [addr])

            SATOSHIS_PER_COIN = 10 ** 8
            value = sum([int(round(s["amount"] * SATOSHIS_PER_COIN)) for s in unspents])

            print >> sys.stderr, "Address %s loaded with %s satoshis" % (addr, value)



    db = state_engine.get_db_state(disposition=state_engine.DISPOSITION_RW)


    # Kill the pid for use this port
    return_code, output = commands.getstatusoutput("netstat -apn | grep %s |  grep python| awk '{print $7}'" % RPC_SERVER_PORT)
    if 'python' in output:
        import re
        pattern = re.compile("(\d+)/python")
        match = pattern.search(output)
        if match:
            port = match.group(1)
        rc = os.system("kill -9 %s" % port)
        if rc != 0:
            log.exception("force kill failed")
            os.abort()

    # Start up the rpc server
    server = VoteServer()
    server.start()


    set_global_server(server)

    while True:
        height = bitcoind.getblockcount()
        log.info("Sync virtualchain up to %s " % height)
        virtualchain.sync_virtualchain(bitcoin_regtest_opts(), height, db)

        # wait for the next block
        deadline = time.time() + REINDEX_FREQUENCY
        while time.time() < deadline:
            try:
                time.sleep(1)
            except:
                break
コード例 #9
0
def get_profile(name,
                zonefile_storage_drivers=None,
                profile_storage_drivers=None,
                proxy=None,
                user_zonefile=None,
                name_record=None,
                include_name_record=False,
                include_raw_zonefile=False,
                use_zonefile_urls=True,
                use_legacy=False,
                use_legacy_zonefile=True,
                decode_profile=True):
    """
    Given a name, look up an associated profile.
    Do so by first looking up the zonefile the name points to,
    and then loading the profile from that zonefile's public key.

    Notes on backwards compatibility (activated if use_legacy=True and use_legacy_zonefile=True):
    
    * (use_legacy=True) If the user's zonefile is really a legacy profile from Onename, then
    the profile returned will be the converted legacy profile.  The returned zonefile will still
    be a legacy profile, however.
    The caller can check this and perform the conversion automatically.

    * (use_legacy_zonefile=True) If the name points to a current zonefile that does not have a 
    data public key, then the owner address of the name will be used to verify
    the profile's authenticity.

    Returns (profile, zonefile) on success.  If include_name_record is True, then zonefile['name_record'] will be defined and will contain the user's blockchain information
    Returns (None, {'error': ...}) on failure
    """

    proxy = get_default_proxy() if proxy is None else proxy

    raw_zonefile = None
    if user_zonefile is None:
        user_zonefile = get_name_zonefile(
            name,
            proxy=proxy,
            name_record=name_record,
            include_name_record=True,
            storage_drivers=zonefile_storage_drivers,
            include_raw_zonefile=include_raw_zonefile,
            allow_legacy=True)

        if 'error' in user_zonefile:
            return None, user_zonefile

        raw_zonefile = None
        if include_raw_zonefile:
            raw_zonefile = user_zonefile.pop('raw_zonefile')

        user_zonefile = user_zonefile['zonefile']

    # is this really a legacy profile?
    if blockstack_profiles.is_profile_in_legacy_format(user_zonefile):
        if not use_legacy:
            return (None, {'error': 'Profile is in legacy format'})

        # convert it
        log.debug('Converting legacy profile to modern profile')
        user_profile = blockstack_profiles.get_person_from_legacy_format(
            user_zonefile)

    elif not user_db.is_user_zonefile(user_zonefile):
        if not use_legacy:
            return (None, {'error': 'Name zonefile is non-standard'})

        # not a legacy profile, but a custom profile
        log.debug('Using custom legacy profile')
        user_profile = copy.deepcopy(user_zonefile)

    else:
        # get user's data public key
        data_address, owner_address = None, None

        try:
            user_data_pubkey = user_db.user_zonefile_data_pubkey(user_zonefile)
            if user_data_pubkey is not None:
                user_data_pubkey = str(user_data_pubkey)
                data_address = virtualchain.BitcoinPublicKey(
                    user_data_pubkey).address()

        except ValueError:
            # multiple keys defined; we don't know which one to use
            user_data_pubkey = None

        if not use_legacy_zonefile and user_data_pubkey is None:
            # legacy zonefile without a data public key
            return (None, {'error': 'Name zonefile is missing a public key'})

        # find owner address
        if name_record is None:
            name_record = get_name_blockchain_record(name, proxy=proxy)
            if name_record is None or 'error' in name_record:
                log.error(
                    'Failed to look up name record for "{}"'.format(name))
                return None, {'error': 'Failed to look up name record'}

        assert 'address' in name_record.keys(), json.dumps(name_record,
                                                           indent=4,
                                                           sort_keys=True)
        owner_address = name_record['address']

        # get user's data public key from the zonefile
        urls = None
        if use_zonefile_urls and user_zonefile is not None:
            urls = user_db.user_zonefile_urls(user_zonefile)

        user_profile = storage.get_mutable_data(
            name,
            user_data_pubkey,
            data_address=data_address,
            owner_address=owner_address,
            urls=urls,
            drivers=profile_storage_drivers,
            decode=decode_profile,
        )

        if user_profile is None or json_is_error(user_profile):
            if user_profile is None:
                log.debug('WARN: no user profile for {}'.format(name))
            else:
                log.debug('WARN: failed to load profile for {}: {}'.format(
                    name, user_profile['error']))

            return None, {'error': 'Failed to load user profile'}

    # finally, if the caller asked for the name record, and we didn't get a chance to look it up,
    # then go get it.
    if include_name_record:
        if name_record is None:
            name_record = get_name_blockchain_record(name, proxy=proxy)

        if name_record is None or 'error' in name_record:
            log.error('Failed to look up name record for "{}"'.format(name))
            return None, {'error': 'Failed to look up name record'}

        user_zonefile['name_record'] = name_record

    if include_raw_zonefile:
        if raw_zonefile is not None:
            user_zonefile['raw_zonefile'] = raw_zonefile

    return user_profile, user_zonefile