Exemplo n.º 1
0
def decrypt_private_key_info( privkey_info, password ):
    """
    Decrypt a particular private key info bundle.
    It can be either a single-signature private key, or a multisig key bundle.
    Return {'address': ..., 'private_key_info': ...} on success.
    Return {'error': ...} on error.
    """
    hex_password = hexlify(password)

    if is_encrypted_multisig( privkey_info ):
        ret = decrypt_multisig_info( privkey_info, password )

        if 'error' in ret:
            return {'error': 'Failed to decrypt multisig wallet: %s' % ret['error']}

        # sanity check
        if 'redeem_script' not in ret:
            return {'error': 'Invalid multisig wallet: missing redeem_script'}

        if 'private_keys' not in ret:
            return {'error': 'Invalid multisig wallet: missing private_keys'}
        
        return {'address': virtualchain.make_p2sh_address(ret['redeem_script']), 'private_key_info': ret}

    elif type(privkey_info) in [str, unicode]:
        try:
            pk = aes_decrypt( privkey_info, hex_password )
            virtualchain.BitcoinPrivateKey(pk)
        except:
            return {'error': 'Invalid password'}

        return {'address': virtualchain.BitcoinPrivateKey(pk).public_key().address(), 'private_key_info': pk}

    else:
        return {'error': 'Invalid encrypted private key info'}
Exemplo n.º 2
0
def make_wallet_keys(data_privkey=None,
                     owner_privkey=None,
                     payment_privkey=None):
    """
    For testing.  DO NOT USE
    """

    ret = {
        'owner_privkey': None,
        'data_privkey': None,
        'payment_privkey': None
    }

    if data_privkey is not None:
        if not is_singlesig(data_privkey):
            raise ValueError("Invalid data key info")

        pk_data = virtualchain.BitcoinPrivateKey(data_privkey).to_hex()
        ret['data_privkey'] = pk_data

    if owner_privkey is not None:
        if is_multisig(owner_privkey):
            pks = [
                virtualchain.BitcoinPrivateKey(pk).to_hex()
                for pk in owner_privkey['private_keys']
            ]
            m, pubs = virtualchain.parse_multisig_redeemscript(
                owner_privkey['redeem_script'])
            ret['owner_privkey'] = virtualchain.make_multisig_info(m, pks)

        elif is_singlesig(owner_privkey):
            pk_owner = virtualchain.BitcoinPrivateKey(owner_privkey).to_hex()
            ret['owner_privkey'] = pk_owner

        else:
            raise ValueError("Invalid owner key info")

    if payment_privkey is not None:
        if is_multisig(payment_privkey):
            pks = [
                virtualchain.BitcoinPrivateKey(pk).to_hex()
                for pk in payment_privkey['private_keys']
            ]
            m, pubs = virtualchain.parse_multisig_redeemscript(
                payment_privkey['redeem_script'])
            ret['payment_privkey'] = virtualchain.make_multisig_info(m, pks)

        elif is_singlesig(payment_privkey):
            pk_payment = virtualchain.BitcoinPrivateKey(
                payment_privkey).to_hex()
            ret['payment_privkey'] = pk_payment

        else:
            raise ValueError("Invalid payment key info")

    return ret
def get_uncompressed_private_and_public_keys(privkey_str):
    """
    Get the private and public keys from a private key string.
    Make sure the both are *uncompressed*
    """
    pk = virtualchain.BitcoinPrivateKey(str(privkey_str))
    pk_hex = pk.to_hex()

    # force uncompressed
    if len(pk_hex) > 64:
        assert pk_hex[-2:] == '01'
        pk_hex = pk_hex[:64]

    pubk_hex = virtualchain.BitcoinPrivateKey(pk_hex).public_key().to_hex()
    return pk_hex, pubk_hex
Exemplo n.º 4
0
def tx_sign_input(blockstack_tx,
                  idx,
                  private_key_info,
                  hashcode=bitcoin.SIGHASH_ALL):
    """
    Sign a particular input in the given transaction.
    @private_key_info can either be a private key, or it can be a dict with 'redeem_script' and 'private_keys' defined
    """
    if type(private_key_info) in [str, unicode]:
        # single private key
        return bitcoin.sign(blockstack_tx,
                            idx,
                            virtualchain.BitcoinPrivateKey(
                                str(private_key_info)).to_hex(),
                            hashcode=hashcode)

    else:
        assert type(private_key_info) in [dict]
        assert "redeem_script" in private_key_info
        assert "private_keys" in private_key_info

        redeem_script = private_key_info['redeem_script']
        private_keys = private_key_info['private_keys']

        assert type(redeem_script) in [str, unicode]
        redeem_script = str(redeem_script)

        # multisig
        return tx_sign_multisig(blockstack_tx,
                                idx,
                                str(redeem_script),
                                private_keys,
                                hashcode=bitcoin.SIGHASH_ALL)
Exemplo n.º 5
0
def decrypt_multisig_info( enc_multisig_info, password ):
    """
    Given an encrypted multisig info dict,
    decrypt the sensitive fields.

    Returns {'private_keys': ..., 'redeem_script': ..., **other_fields}
    Return {'error': ...} on error
    """
    multisig_info = {}
    hex_password = hexlify(password)

    if 'encrypted_private_keys' in enc_multisig_info.keys():
        multisig_info['private_keys'] = []
        for enc_pk in enc_multisig_info['encrypted_private_keys']:
            pk = None
            try:
                pk = aes_decrypt( enc_pk, hex_password )
                virtualchain.BitcoinPrivateKey(pk)
            except Exception, e:
                if os.environ.get("BLOCKSTACK_TEST", None) == "1":
                    log.exception(e)

                return {'error': 'Invalid password; failed to decrypt private key in multisig wallet'}
                
            multisig_info['private_keys'].append( pk )
Exemplo n.º 6
0
def encrypt_private_key_info(privkey_info, password):
    """
    Encrypt private key info.
    Return {'status': True, 'encrypted_private_key_info': {'address': ..., 'private_key_info': ...}} on success
    Returns {'error': ...} on error
    """

    ret = {}
    hex_password = hexlify(password)

    if is_multisig(privkey_info):
        ret['address'] = virtualchain.make_multisig_address(
            privkey_info['redeem_script'])
        ret['private_key_info'] = encrypt_multisig_info(privkey_info, password)

        return {'status': True, 'encrypted_private_key_info': ret}

    elif is_singlesig(privkey_info):
        ret['address'] = virtualchain.BitcoinPrivateKey(
            privkey_info).public_key().address()
        ret['private_key_info'] = aes_encrypt(privkey_info, hex_password)

        return {'status': True, 'encrypted_private_key_info': ret}

    else:
        return {'error': 'Invalid private key info'}
Exemplo n.º 7
0
def tx_make_input_signature(tx, idx, script, privkey_str, hashcode):
    """
    Sign a single input of a transaction, given the serialized tx,
    the input index, the output's scriptPubkey, and the hashcode.

    privkey_str must be a hex-encoded private key

    TODO: move to virtualchain

    Return the hex signature.
    """
    pk = virtualchain.BitcoinPrivateKey(str(privkey_str))
    pubk = pk.public_key()

    priv = pk.to_hex()
    pub = pubk.to_hex()
    addr = pubk.address()

    signing_tx = bitcoin.signature_form(tx, idx, script, hashcode)
    txhash = bitcoin.bin_txhash(signing_tx, hashcode)

    # sign using uncompressed private key
    pk_uncompressed_hex, pubk_uncompressed_hex = get_uncompressed_private_and_public_keys(
        priv)
    sigb64 = sign_digest(txhash.encode('hex'), priv)

    # sanity check
    assert verify_digest(txhash.encode('hex'), pubk_uncompressed_hex, sigb64)

    sig_r, sig_s = decode_signature(sigb64)
    sig_bin = ecdsa.util.sigencode_der(sig_r, sig_s, ecdsa.SECP256k1.order)
    sig = sig_bin.encode('hex') + bitcoin.encode(hashcode, 16, 2)
    return sig
def mktx( amt, tx_fee, recipient_addr, privkey, message=None ):
    """
    Make the transaction with the given fee
    """
    change_addr = virtualchain.BitcoinPrivateKey(privkey).public_key().address()
    inputs = testlib.get_unspents(change_addr)
    change = virtualchain.calculate_change_amount(inputs, amt, tx_fee)

    outputs = [
        {'script': virtualchain.make_payment_script(recipient_addr),
         'value': amt},
    ]

    if change > 0:
        # need change and tx fee
        outputs.append( 
            {'script': virtualchain.make_payment_script(change_addr),
              "value": change}
        )

    if message:
        outputs = [
            {"script": virtualchain.make_data_script(binascii.hexlify(message)),
             "value": 0} ] + outputs

    serialized_tx = blockstack_client.tx.serialize_tx(inputs, outputs)
    signed_tx = blockstack_client.tx.sign_tx(serialized_tx, privkey)
    return signed_tx
Exemplo n.º 9
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)

    # derive importer keys and do imports
    # NOTE: breaks consensus trace from 0.14.0
    private_keychain = keychain.PrivateKeychain.from_private_key(
        wallets[1].privkey)
    private_keys = [
        wallets[1].privkey
    ]  # NOTE: always start with the reveal key, then use children
    for i in xrange(0, 3):
        import_key = private_keychain.child(i).private_key()

        print "fund {} (child {})".format(import_key, i)
        res = testlib.send_funds(
            wallets[1].privkey, 100000000,
            virtualchain.BitcoinPrivateKey(import_key).public_key().address())
        if 'error' in res:
            print json.dumps(res, indent=4, sort_keys=True)
            return False

        testlib.next_block(**kw)
        private_keys.append(import_key)

    resp = testlib.blockstack_name_import(
        "foo.test", addr_reencode("1BKufFedDrueBBFBXtiATB2PSdsBGZxf3N"),
        "11" * 20, wallets[1].privkey)  # master
    if 'error' in resp:
        print json.dumps(resp, indent=4)

    testlib.next_block(**kw)

    resp = testlib.blockstack_name_import(
        "foo.test", addr_reencode("1ARVjrtKnUVWt2GNrpuFLnNCL2WGUhKdkW"),
        "33" * 20, private_keys[2])  # derived child 2
    if 'error' in resp:
        print json.dumps(resp, indent=4)

    testlib.next_block(**kw)

    resp = testlib.blockstack_name_import(
        "foo.test", addr_reencode("1PYu4vKB3g2QLDFdurxqYSJ9aJSed7tne1"),
        "22" * 20, private_keys[1])  # derived child 1
    if 'error' in resp:
        print json.dumps(resp, indent=4)

    testlib.next_block(**kw)

    testlib.blockstack_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)
Exemplo n.º 10
0
def tx_sign_multisig(blockstack_tx,
                     idx,
                     redeem_script,
                     private_keys,
                     hashcode=bitcoin.SIGHASH_ALL):
    """
    Sign a p2sh multisig input.
    Return the signed transaction
    """

    # sign in the right order
    privs = dict([
        (virtualchain.BitcoinPrivateKey(str(pk_str)).public_key().to_hex(),
         str(pk_str)) for pk_str in private_keys
    ])
    m, public_keys = virtualchain.parse_multisig_redeemscript(
        str(redeem_script))

    used_keys = []
    sigs = []

    for ki in xrange(0, len(public_keys)):
        if not privs.has_key(public_keys[ki]):
            continue

        if len(used_keys) == m:
            break

        assert public_keys[
            ki] not in used_keys, "Tried to reuse key %s" % public_keys[ki]

        pk_str = privs[public_keys[ki]]
        used_keys.append(public_keys[ki])

        pk_hex = virtualchain.BitcoinPrivateKey(str(pk_str)).to_hex()
        sig = bitcoin.multisign(blockstack_tx,
                                idx,
                                str(redeem_script),
                                pk_hex,
                                hashcode=hashcode)
        sigs.append(sig)

    assert len(used_keys) == m, "Missing private keys"

    return bitcoin.apply_multisignatures(blockstack_tx, idx,
                                         str(redeem_script), sigs)
Exemplo n.º 11
0
def multisig_privkey_to_string(privkey_info):
    """
    Convert multisig keys to string
    """
    return ",".join([
        virtualchain.BitcoinPrivateKey(pk).to_wif()
        for pk in privkey_info['private_keys']
    ])
Exemplo n.º 12
0
def decrypt_multisig_info(enc_multisig_info, password):
    """
    Given an encrypted multisig info dict,
    decrypt the sensitive fields.

    Returns {'private_keys': ..., 'redeem_script': ..., **other_fields}
    Return {'error': ...} on error
    """
    multisig_info = {
        'private_keys': None,
        'redeem_script': None,
    }

    hex_password = hexlify(password)

    assert is_encrypted_multisig(
        enc_multisig_info), 'Invalid encrypted multisig keys'

    multisig_info['private_keys'] = []
    for enc_pk in enc_multisig_info['encrypted_private_keys']:
        pk = None
        try:
            pk = aes_decrypt(enc_pk, hex_password)
            virtualchain.BitcoinPrivateKey(pk)
        except Exception as e:
            if BLOCKSTACK_TEST:
                log.exception(e)

            return {
                'error':
                'Invalid password; failed to decrypt private key in multisig wallet'
            }

        multisig_info['private_keys'].append(ECPrivateKey(pk).to_hex())

    redeem_script = None
    enc_redeem_script = enc_multisig_info['encrypted_redeem_script']
    try:
        redeem_script = aes_decrypt(enc_redeem_script, hex_password)
    except Exception as e:
        if BLOCKSTACK_TEST:
            log.exception(e)

        return {
            'error':
            'Invalid password; failed to decrypt redeem script in multisig wallet'
        }

    multisig_info['redeem_script'] = redeem_script

    # preserve any other information in the multisig info
    for k, v in enc_multisig_info.items():
        if k not in ['encrypted_private_keys', 'encrypted_redeem_script']:
            multisig_info[k] = v

    return multisig_info
Exemplo n.º 13
0
def get_privkey_info_address(privkey_info):
    if privkey_info is None:
        return None

    if is_singlesig(privkey_info):
        return virtualchain.BitcoinPrivateKey(
            privkey_info).public_key().address()

    else:
        raise ValueError("Invalid private key info")
def make_transaction(name, payment_privkey_info, consensus_hash, payment_addr,
                     zonefilemanage_client):

    data = build(name)
    tx = make_op_return_tx(
        data,
        virtualchain.BitcoinPrivateKey(payment_privkey_info),
        zonefilemanage_client,
        fee=100000,
        format='bin')
    return tx
Exemplo n.º 15
0
def tx_sign_multisig(tx,
                     idx,
                     redeem_script,
                     private_keys,
                     hashcode=bitcoin.SIGHASH_ALL):
    """
    Sign a p2sh multisig input.
    Return the signed transaction

    TODO: move to virtualchain
    """
    # sign in the right order
    privs = {
        virtualchain.BitcoinPrivateKey(str(pk)).public_key().to_hex(): str(pk)
        for pk in private_keys
    }
    m, public_keys = virtualchain.parse_multisig_redeemscript(
        str(redeem_script))

    used_keys, sigs = [], []
    for public_key in public_keys:
        if public_key not in privs:
            continue

        if len(used_keys) == m:
            break

        assert public_key not in used_keys, 'Tried to reuse key {}'.format(
            public_key)

        pk_str = privs[public_key]
        used_keys.append(public_key)

        pk_hex = virtualchain.BitcoinPrivateKey(str(pk_str)).to_hex()

        sig = tx_make_input_signature(tx, idx, redeem_script, pk_str, hashcode)
        # sig = bitcoin.multisign(tx, idx, str(redeem_script), pk_hex, hashcode=hashcode)
        sigs.append(sig)

    assert len(used_keys) == m, 'Missing private keys'
    return bitcoin.apply_multisignatures(tx, idx, str(redeem_script), sigs)
Exemplo n.º 16
0
def is_singlesig(privkey_info):
    """
    Does the given private key info represent
    a single signature bundle? (i.e. one private key)?
    """
    if type(privkey_info) not in [str, unicode]:
        return False

    try:
        virtualchain.BitcoinPrivateKey(privkey_info)
        return True
    except:
        return False
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
Exemplo n.º 18
0
def get_data_or_owner_privkey(user_zonefile,
                              owner_address,
                              wallet_keys=None,
                              config_path=CONFIG_PATH):
    """
    Get the data private key if it is set in the zonefile, or if not, fall back to the 
    owner private key.
    
    Due to legacy compatibility

    Useful for signing mutable data when no explicit data key is set.
    Returns {'status': True, 'privatekey': ...} on success
    Returns {'error': ...} on error
    """

    # generate the mutable zonefile
    data_privkey = get_data_privkey(user_zonefile,
                                    wallet_keys=wallet_keys,
                                    config_path=config_path)
    if data_privkey is None:
        # This is legacy code here.  The only time this should happen is
        # when the user has a single owner key, and does not have a
        # separate data key.
        log.warn("No data private key set.  Falling back to owner keypair.")
        owner_privkey_info = get_owner_privkey_info(wallet_keys=wallet_keys,
                                                    config_path=config_path)
        if owner_privkey_info is None:
            raise Exception("No owner private key info")
            return {'error': 'No usable private signing key found'}

        # sanity check: must be a single private key
        if not is_singlesig(owner_privkey_info):
            raise Exception("Owner private key info must be a single key")
            return {'error': 'No usable private signing key found'}

        # sanity check: must match profile address
        owner_pubkey = virtualchain.BitcoinPrivateKey(
            owner_privkey_info).public_key().to_hex()
        compressed_addr, uncompressed_addr = get_pubkey_addresses(owner_pubkey)
        if owner_address not in [compressed_addr, uncompressed_addr]:
            raise Exception(
                "%s not in [%s,%s]" %
                (owner_address, compressed_addr, uncompressed_addr))
            return {'error': 'No usable public key'}

        data_privkey = owner_privkey_info

    return {'status': True, 'privatekey': data_privkey}
Exemplo n.º 19
0
def decrypt_private_key_info(privkey_info, password):
    """
    Decrypt a particular private key info bundle.
    It can be either a single-signature private key, or a multisig key bundle.
    Return {'address': ..., 'private_key_info': ...} on success.
    Return {'error': ...} on error.
    """
    hex_password = hexlify(password)

    ret = {}
    if is_encrypted_multisig(privkey_info):
        ret = decrypt_multisig_info(privkey_info, password)

        if 'error' in ret:
            return {
                'error':
                'Failed to decrypt multisig wallet: {}'.format(ret['error'])
            }

        # sanity check
        if 'redeem_script' not in ret:
            return {'error': 'Invalid multisig wallet: missing redeem_script'}

        if 'private_keys' not in ret:
            return {'error': 'Invalid multisig wallet: missing private_keys'}

        return {
            'address': virtualchain.make_p2sh_address(ret['redeem_script']),
            'private_key_info': ret
        }

    if is_encrypted_singlesig(privkey_info):
        try:
            pk = aes_decrypt(privkey_info, hex_password)
            pk = ECPrivateKey(pk).to_hex()
        except Exception as e:
            if BLOCKSTACK_TEST:
                log.exception(e)

            return {'error': 'Invalid password'}

        return {
            'address':
            virtualchain.BitcoinPrivateKey(pk).public_key().address(),
            'private_key_info': pk
        }

    return {'error': 'Invalid encrypted private key info'}
    def __init__(self, pk_wif, ignored):

        pk = virtualchain.BitcoinPrivateKey(pk_wif)

        self._pk = pk

        if pk_wif.startswith("c"):
            #already a privkey
            self.privkey = pk_wif
        else:
            self.privkey = pk.to_wif()

        self.pubkey_hex = pk.public_key().to_hex()
        self.addr = pk.public_key().address()

        log.info("Wallet %s(%s)" % (self.privkey, self.addr))
Exemplo n.º 21
0
def tx_make_input_signature(tx, idx, script, privkey_str, hashcode):
    """
    Sign a single input of a transaction, given the serialized tx,
    the input index, the output's scriptPubkey, and the hashcode.

    TODO: move to virtualchain

    Return the hex signature.
    """

    pk = virtualchain.BitcoinPrivateKey(str(privkey_str))
    pubk = pk.public_key()

    priv = pk.to_hex()
    pub = pubk.to_hex()
    addr = pubk.address()

    signing_tx = bitcoin.signature_form(tx, idx, script, hashcode)
    txhash = bitcoin.bin_txhash(signing_tx, hashcode)

    # sign using uncompressed private key
    pk_uncompressed_hex, pubk_uncompressed_hex = get_uncompressed_private_and_public_keys(
        priv)

    sk = ecdsa.SigningKey.from_string(pk_uncompressed_hex.decode('hex'),
                                      curve=ecdsa.SECP256k1)
    sig_bin = sk.sign_digest(txhash, sigencode=ecdsa.util.sigencode_der)

    # enforce low-s
    sig_r, sig_s = ecdsa.util.sigdecode_der(sig_bin, ecdsa.SECP256k1.order)
    if sig_s * 2 >= ecdsa.SECP256k1.order:
        log.debug("High-S to low-S")
        sig_s = ecdsa.SECP256k1.order - sig_s

    sig_bin = ecdsa.util.sigencode_der(sig_r, sig_s, ecdsa.SECP256k1.order)

    # sanity check
    vk = ecdsa.VerifyingKey.from_string(
        pubk_uncompressed_hex[2:].decode('hex'), curve=ecdsa.SECP256k1)
    assert vk.verify_digest(sig_bin,
                            txhash,
                            sigdecode=ecdsa.util.sigdecode_der
                            ), "Failed to verify signature ({}, {})".format(
                                sig_r, sig_s)

    sig = sig_bin.encode('hex') + bitcoin.encode(hashcode, 16, 2)
    return sig
Exemplo n.º 22
0
def get_privkey_info_address( privkey_info ):
    """
    Get the address of private key information:
    * if it's a single private key, then calculate the address.
    * if it's a multisig info dict, then get the p2sh address
    """
    if privkey_info is None:
        return None

    if is_singlesig(privkey_info):
        return virtualchain.BitcoinPrivateKey(privkey_info).public_key().address()

    elif is_multisig(privkey_info):
        return virtualchain.make_multisig_address( privkey_info['redeem_script'] )

    else:
        raise ValueError("Invalid private key info")
Exemplo n.º 23
0
def do_name_register(name,
                     payment_privkey_info,
                     utxo_client,
                     tx_broadcaster,
                     consensus_hash=None,
                     proxy=None,
                     safety_check=None):
    db = get_default_db_inst()
    records = db.get_name(name)
    if records is not None:
        log.error("The name %s has been registered" % name)
        return {"error": "Name %s has already exist" % name}

    try:
        payment_address = virtualchain.BitcoinPrivateKey(
            payment_privkey_info).public_key().address()
    except Exception, e:
        log.error("Invalid private key info")
        return {
            'error':
            'Name register can only use a single private key with a P2PKH script'
        }
Exemplo n.º 24
0
def tx_sign_singlesig(tx, idx, private_key_info, hashcode=bitcoin.SIGHASH_ALL):
    """
    Sign a p2pkh input
    Return the signed transaction

    TODO: move to virtualchain

    NOTE: implemented here instead of bitcoin, since bitcoin.sign() can cause a stack overflow
    while converting the private key to a public key.
    """
    pk = virtualchain.BitcoinPrivateKey(str(private_key_info))
    pubk = pk.public_key()

    pub = pubk.to_hex()
    addr = pubk.address()

    script = virtualchain.make_payment_script(addr)
    sig = tx_make_input_signature(tx, idx, script, private_key_info, hashcode)

    txobj = bitcoin.deserialize(str(tx))
    txobj['ins'][idx]['script'] = bitcoin.serialize_script([sig, pub])
    return bitcoin.serialize(txobj)
Exemplo n.º 25
0
def make_transaction(name, payment_privkey_info, owner_address,
                     zonefilemanage_client):

    data = build(name)
    private_key_obj, from_address, inputs = analyze_private_key(
        virtualchain.BitcoinPrivateKey(payment_privkey_info),
        zonefilemanage_client)
    outputs = make_op_return_outputs(data,
                                     inputs,
                                     from_address,
                                     owner_address,
                                     fee=100000)

    # serialize the transaction
    unsigned_tx = serialize_transaction(inputs, outputs)

    # generate a scriptSig for each input
    for i in xrange(0, len(inputs)):
        signed_tx = sign_transaction(unsigned_tx, i, private_key_obj.to_hex())
        unsigned_tx = signed_tx

    # return the signed tx
    return signed_tx
def scenario(wallets, **kw):

    # make a test namespace
    resp = testlib.blockstack_namespace_preorder("test", wallets[1].addr,
                                                 wallets[0].privkey)
    if 'error' in resp:
        print json.dumps(resp, indent=4)
        return False

    testlib.next_block(**kw)

    resp = 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 resp:
        print json.dumps(resp, indent=4)
        return False

    testlib.next_block(**kw)

    # import 3 names in the same block: foo.test, bar.test, baz.test
    names = ['foo.test', 'bar.test', 'baz.test']
    name_preorder_wallets = [wallets[2], wallets[3], wallets[4]]
    name_register_wallets = [wallets[5], wallets[6], wallets[7]]
    name_transfer_wallets = [wallets[6], wallets[7], wallets[5]]

    # derive importer keys and do imports
    # NOTE: breaks consensus trace from 0.14.0
    private_keychain = keychain.PrivateKeychain.from_private_key(
        wallets[1].privkey)
    private_keys = [
        wallets[1].privkey
    ]  # NOTE: always start with the reveal key, then use children
    for i in xrange(0, len(names) - 1):
        import_key = private_keychain.child(i).private_key()

        print "fund {} (child {})".format(import_key, i)
        res = testlib.send_funds(
            wallets[1].privkey, 100000000,
            virtualchain.BitcoinPrivateKey(import_key).public_key().address())
        if 'error' in res:
            print json.dumps(res, indent=4, sort_keys=True)
            return False

        testlib.next_block(**kw)
        private_keys.append(import_key)

    for i in xrange(0, len(names)):

        name = names[i]
        register_wallet = name_register_wallets[i]
        import_key = private_keys[i]

        resp = testlib.blockstack_name_import(name, register_wallet.addr,
                                              str(9 - i) * 40, import_key)
        if 'error' in resp:
            print json.dumps(resp, indent=4)
            return False

    testlib.next_block(**kw)

    # namespace ready...
    resp = testlib.blockstack_namespace_ready("test", wallets[1].privkey)
    if 'error' in resp:
        print json.dumps(resp, indent=4)
        return False

    testlib.next_block(**kw)

    # update 3 names in the same block
    for i in xrange(0, len(names)):

        name = names[i]
        register_wallet = name_register_wallets[i]

        resp = testlib.blockstack_name_update(name,
                                              str(i + 2) * 40,
                                              register_wallet.privkey)
        if 'error' in resp:
            print json.dumps(resp, indent=4)
            return False

    testlib.next_block(**kw)

    # update 3 names in the same block, again
    for i in xrange(0, len(names)):

        name = names[i]
        register_wallet = name_register_wallets[i]

        resp = testlib.blockstack_name_update(name,
                                              str(i + 1) * 40,
                                              register_wallet.privkey)
        if 'error' in resp:
            print json.dumps(resp, indent=4)
            return False

    testlib.next_block(**kw)

    # transfer 3 names in the same block
    for i in xrange(0, len(names)):

        name = names[i]
        register_wallet = name_register_wallets[i]
        transfer_wallet = name_transfer_wallets[i]

        resp = testlib.blockstack_name_transfer(name, transfer_wallet.addr,
                                                True, register_wallet.privkey)
        if 'error' in resp:
            print json.dumps(resp, indent=4)
            return False

    testlib.next_block(**kw)

    # exchange after transfer...
    tmp = name_register_wallets
    name_register_wallets = name_transfer_wallets
    name_transfer_wallets = tmp

    # revoke 3 names in the same block
    for i in xrange(0, len(names)):

        name = names[i]
        register_wallet = name_register_wallets[i]

        resp = testlib.blockstack_name_revoke(name, register_wallet.privkey)
        if 'error' in resp:
            print json.dumps(resp, indent=4)
            return False

    # iterate the blocks a few times
    for i in xrange(0, 5):
        testlib.next_block(**kw)
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):

    print '\nactivating segwit\n'

    virtualchain.set_features("segwit", True)

    print '\nsegwit state: {}\n'.format(virtualchain.get_features('segwit'))

    testlib.blockstack_namespace_preorder("test", wallets[1].addr,
                                          wallets[5].privkey)
    testlib.blockstack_namespace_preorder("mult", wallets[2].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[5].privkey)
    testlib.blockstack_namespace_reveal(
        "mult",
        wallets[2].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,
        version_bits=2)
    testlib.next_block(**kw)

    private_keychain = keychain.PrivateKeychain.from_private_key(
        wallets[2].privkey)
    private_keys = [
        wallets[2].privkey
    ]  # NOTE: always start with the reveal key, then use children
    for i in xrange(0, 4):
        import_key = private_keychain.child(i).private_key()

        print "fund {} (child {})".format(import_key, i)
        res = testlib.send_funds(
            wallets[1].privkey, 100000000,
            virtualchain.BitcoinPrivateKey(import_key).public_key().address())
        if 'error' in res:
            print json.dumps(res, indent=4, sort_keys=True)
            return False

        testlib.next_block(**kw)
        private_keys.append(import_key)

    # should succeed
    resp = testlib.blockstack_name_import("foo.mult", wallets[2].addr,
                                          '00' * 20, private_keys[0])
    if 'error' in resp:
        print json.dumps(resp, indent=4, sort_keys=True)
        return False

    testlib.next_block(**kw)

    # should succeed
    resp = testlib.blockstack_name_import("bar.mult", wallets[3].addr,
                                          "11" * 20, private_keys[1])
    if 'error' in resp:
        print json.dumps(resp, indent=4, sort_keys=True)
        return False

    # should succeed
    resp = testlib.blockstack_name_import("baz.mult", wallets[4].addr,
                                          "22" * 20, private_keys[2])
    if 'error' in resp:
        print json.dumps(resp, indent=4, sort_keys=True)
        return False

    # should succeed
    resp = testlib.blockstack_name_import("goo.mult", wallets[5].addr,
                                          "33" * 20, private_keys[3])
    if 'error' in resp:
        print json.dumps(resp, indent=4, sort_keys=True)
        return False

    testlib.next_block(**kw)

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

    namespace_balance = testlib.get_balance(wallets[0].addr)

    # get prices
    hello_cost = testlib.blockstack_get_name_cost('hello.mult')
    world_cost = testlib.blockstack_get_name_cost('world.mult')
    foo_cost = testlib.blockstack_get_name_cost('foo.mult')

    # register/renew
    res = testlib.blockstack_name_preorder("hello.mult", wallets[1].privkey,
                                           wallets[2].addr)
    if 'error' in res:
        print res
        return False

    res = testlib.blockstack_name_preorder('world.mult',
                                           wallets[6].privkey,
                                           wallets[7].addr,
                                           wallet=wallets[7])
    if 'error' in res:
        print res
        return False

    res = testlib.blockstack_name_renew('foo.mult', wallets[2].privkey)
    if 'error' in res:
        print res
        return False

    testlib.next_block(**kw)

    new_namespace_balance = testlib.get_balance(wallets[0].addr)

    if new_namespace_balance != namespace_balance + hello_cost + world_cost + foo_cost:
        print 'wrong balance'
        print new_namespace_balance
        print namespace_balance
        print hello_cost
        print foo_cost
        return False

    res = testlib.blockstack_name_register("hello.mult", wallets[1].privkey,
                                           wallets[2].addr)
    if 'error' in res:
        print res
        return False

    res = testlib.blockstack_name_register('world.mult',
                                           wallets[6].privkey,
                                           wallets[7].addr,
                                           wallet=wallets[7],
                                           zonefile_hash='44' * 20)
    if 'error' in res:
        print res
        return False

    testlib.next_block(**kw)
Exemplo n.º 29
0
def singlesig_privkey_to_string( privkey_info ):
    """
    Convert private key to string
    """
    return virtualchain.BitcoinPrivateKey(privkey_info).to_wif()
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