Esempio n. 1
0
def blockstore_script_to_hex(script):
    """ Parse the readable version of a script, return the hex version.
    """
    hex_script = ''
    parts = script.split(' ')
    for part in parts:
       
        if part.startswith("NAME_") or part.startswith("NAMESPACE_"):
            try:
                hex_script += '%0.2x' % ord(eval(part))
            except:
                raise Exception('Invalid opcode: %s' % part)
        
        elif part.startswith("0x"):
            # literal hex string
            hex_script += part[2:]
            
        elif is_valid_int(part):
            hex_part = '%0.2x' % int(part)
            if len(hex_part) % 2 != 0:
               hex_part = '0' + hex_part
               
            hex_script += hex_part
         
        elif is_hex(part) and len(part) % 2 == 0:
            hex_script += part
            
        else:
            raise ValueError('Invalid script (at %s), contains invalid characters: %s' % (part, script))
         
    if len(hex_script) % 2 != 0:
        raise ValueError('Invalid script: must have an even number of chars (got %s).' % hex_script)
     
    return hex_script
Esempio n. 2
0
def parse_nameop_data(data):
    if not is_hex(data):
        raise ValueError('Data must be hex')
    # if not len(data) <= OP_RETURN_MAX_SIZE*2:
    #    raise ValueError('Payload too large')
    if not len(data) % 2 == 0:
        # raise ValueError('Data must have an even number of bytes')
        return None

    try:
        bin_data = unhexlify(data)
    except:
        raise Exception('Invalid data supplied: %s' % data)

    magic_bytes, opcode, payload = bin_data[0:2], bin_data[2:3], bin_data[3:]

    if not magic_bytes == MAGIC_BYTES:
        # Magic bytes don't match - not an openname operation.
        return None

    if opcode == NAME_PREORDER and len(payload) >= MIN_OP_LENGTHS['preorder']:
        nameop = parse_preorder(payload)
    elif (opcode == NAME_REGISTRATION
            and len(payload) >= MIN_OP_LENGTHS['registration']):
        nameop = parse_registration(payload)
    elif opcode == NAME_UPDATE and len(payload) >= MIN_OP_LENGTHS['update']:
        nameop = parse_update(payload)
    elif (opcode == NAME_TRANSFER
          and len(payload) >= MIN_OP_LENGTHS['transfer']):
        nameop = parse_transfer(payload)
    else:
        nameop = None

    return nameop
Esempio n. 3
0
def get_public_key_format(public_key_string):
    if not isinstance(public_key_string, str):
        raise ValueError('Public key must be a string.')

    if len(public_key_string) == 64:
        return CharEncoding.bin, PubkeyType.ecdsa

    if (len(public_key_string) == 65 and
            public_key_string[0] == PUBKEY_MAGIC_BYTE):
        return CharEncoding.bin, PubkeyType.uncompressed

    if len(public_key_string) == 33:
        return CharEncoding.bin, PubkeyType.compressed

    if is_hex(public_key_string):
        if len(public_key_string) == 128:
            return CharEncoding.hex, PubkeyType.ecdsa

        if (len(public_key_string) == 130 and
                public_key_string[0:2] == hexlify(PUBKEY_MAGIC_BYTE)):
            return CharEncoding.hex, PubkeyType.uncompressed

        if len(public_key_string) == 66:
            return CharEncoding.hex, PubkeyType.compressed

    raise ValueError(_errors['IMPROPER_PUBLIC_KEY_FORMAT'])
Esempio n. 4
0
def make_transaction(message_hash,
                     payment_addr,
                     blockchain_client,
                     tx_fee=0,
                     subsidize=False,
                     safety=True):

    message_hash = str(message_hash)
    payment_addr = str(payment_addr)
    tx_fee = int(tx_fee)

    # sanity check
    if len(message_hash) != 40:
        raise Exception("Invalid message hash: not 20 bytes")

    if not is_hex(message_hash):
        raise Exception("Invalid message hash: not hex")

    inputs = None
    private_key_obj = None

    inputs = tx_get_unspents(payment_addr, blockchain_client)
    if safety:
        assert len(inputs) > 0

    nulldata = build(message_hash)
    outputs = make_outputs(nulldata,
                           inputs,
                           payment_addr,
                           tx_fee,
                           pay_fee=(not subsidize))

    return (inputs, outputs)
Esempio n. 5
0
def blockstack_script_to_hex(script):
    """ Parse the readable version of a script, return the hex version.
    """
    hex_script = ''
    parts = script.split(' ')
    for part in parts:
       
        if part in NAME_OPCODES.keys():
            try:
                hex_script += '%0.2x' % ord(NAME_OPCODES[part])
            except:
                raise Exception('Invalid opcode: %s' % part)
        
        elif part.startswith("0x"):
            # literal hex string
            hex_script += part[2:]
            
        elif is_valid_int(part):
            hex_part = '%0.2x' % int(part)
            if len(hex_part) % 2 != 0:
               hex_part = '0' + hex_part
               
            hex_script += hex_part
         
        elif is_hex(part) and len(part) % 2 == 0:
            hex_script += part
            
        else:
            raise ValueError('Invalid script (at %s), contains invalid characters: %s' % (part, script))
         
    if len(hex_script) % 2 != 0:
        raise ValueError('Invalid script: must have an even number of chars (got %s).' % hex_script)
     
    return hex_script
Esempio n. 6
0
def load_verifying_key(verifying_key, crypto_backend=default_backend()):
    """ Optional: crypto backend object from the "cryptography" python library
    """
    if not isinstance(crypto_backend, (Backend, MultiBackend)):
        raise ValueError('backend must be a valid Backend object')

    if isinstance(verifying_key, EllipticCurvePublicKey):
        return verifying_key
    elif isinstance(verifying_key, (str, unicode)):
        if is_hex(verifying_key):
            try:
                public_key_pem = ECPublicKey(verifying_key).to_pem()
            except:
                pass
            else:
                try:
                    return load_pem_public_key(public_key_pem,
                                               backend=crypto_backend)
                except Exception as e:
                    traceback.print_exc()
                    raise InvalidPublicKeyError()

            try:
                return load_der_public_key(verifying_key,
                                           backend=crypto_backend)
            except:
                raise InvalidPublicKeyError()
        else:
            try:
                return load_pem_public_key(verifying_key,
                                           backend=crypto_backend)
            except Exception as e:
                raise InvalidPublicKeyError()
    else:
        raise ValueError('Verifying key must be in string or unicode format.')
Esempio n. 7
0
def build(name, consensus_hash, data_hash=None, testset=False):
    """
    Takes in the name to update the data for and the data update itself.
    Name must include the namespace ID, but not the scheme.
    
    Record format:
    
    0     2  3                                   19                      39
    |-----|--|-----------------------------------|-----------------------|
    magic op  hash128(name.ns_id,consensus hash) hash160(data)
    """

    if not is_b40(name) or "+" in name or name.count(".") > 1:
        raise Exception("Name '%s' has non-base-38 characters" % name)

    if not is_hex(data_hash):
        raise Exception("Invalid hex string '%s': not hex" % (data_hash))

    if len(data_hash) != 2 * LENGTHS['update_hash']:
        raise Exception("Invalid hex string '%s': bad length" % (data_hash))

    hex_name = hash256_trunc128(name + consensus_hash)

    readable_script = 'NAME_UPDATE 0x%s 0x%s' % (hex_name, data_hash)
    hex_script = blockstore_script_to_hex(readable_script)
    packaged_script = add_magic_bytes(hex_script, testset=testset)

    return packaged_script
Esempio n. 8
0
def get_public_key_format(public_key_string):
    if not isinstance(public_key_string, str):
        raise ValueError('Public key must be a string.')

    if len(public_key_string) == 64:
        return CharEncoding.bin, PubkeyType.ecdsa

    if (len(public_key_string) == 65
            and public_key_string[0] == PUBLIC_KEY_MAGIC_BYTE):
        return CharEncoding.bin, PubkeyType.uncompressed

    if len(public_key_string) == 33:
        return CharEncoding.bin, PubkeyType.compressed

    if is_hex(public_key_string):
        if len(public_key_string) == 128:
            return CharEncoding.hex, PubkeyType.ecdsa

        if (len(public_key_string) == 130
                and public_key_string[0:2] == hexlify(PUBLIC_KEY_MAGIC_BYTE)):
            return CharEncoding.hex, PubkeyType.uncompressed

        if len(public_key_string) == 66:
            return CharEncoding.hex, PubkeyType.compressed

    raise InvalidPublicKeyError()
Esempio n. 9
0
def build(name, consensus_hash, data_hash=None, testset=False):
    """
    Takes in the name to update the data for and the data update itself.
    Name must include the namespace ID, but not the scheme.
    
    Record format:
    
    0     2  3                                   19                      39
    |-----|--|-----------------------------------|-----------------------|
    magic op  hash128(name.ns_id,consensus hash) hash160(data)
    """
    
    if not is_b40( name ) or "+" in name or name.count(".") > 1:
       raise Exception("Name '%s' has non-base-38 characters" % name)
   
    if not is_hex( data_hash ):
       raise Exception("Invalid hex string '%s': not hex" % (data_hash))
    
    if len(data_hash) != 2 * LENGTHS['update_hash']:
       raise Exception("Invalid hex string '%s': bad length" % (data_hash))
       
    hex_name = hash256_trunc128( name + consensus_hash )
    
    readable_script = 'NAME_UPDATE 0x%s 0x%s' % (hex_name, data_hash)
    hex_script = blockstore_script_to_hex(readable_script)
    packaged_script = add_magic_bytes(hex_script, testset=testset)

    return packaged_script
Esempio n. 10
0
def parse_nameop_data(data):
    if not is_hex(data):
        raise ValueError('Data must be hex')
    # if not len(data) <= OP_RETURN_MAX_SIZE*2:
    #    raise ValueError('Payload too large')
    if not len(data) % 2 == 0:
        # raise ValueError('Data must have an even number of bytes')
        return None

    try:
        bin_data = unhexlify(data)
    except:
        raise Exception('Invalid data supplied: %s' % data)

    magic_bytes, opcode, payload = bin_data[0:2], bin_data[2:3], bin_data[3:]

    if not magic_bytes == MAGIC_BYTES:
        # Magic bytes don't match - not an openname operation.
        return None

    if opcode == NAME_PREORDER and len(payload) >= MIN_OP_LENGTHS['preorder']:
        nameop = parse_preorder(payload)
    elif (opcode == NAME_REGISTRATION
          and len(payload) >= MIN_OP_LENGTHS['registration']):
        nameop = parse_registration(payload)
    elif opcode == NAME_UPDATE and len(payload) >= MIN_OP_LENGTHS['update']:
        nameop = parse_update(payload)
    elif (opcode == NAME_TRANSFER
          and len(payload) >= MIN_OP_LENGTHS['transfer']):
        nameop = parse_transfer(payload)
    else:
        nameop = None

    return nameop
def zonefilemanage_script_to_hex(script):
    """ Parse the readable version of a script, return the hex version.
    """
    hex_script = ''
    parts = script.split(' ')
    for part in parts:
        if part in NAME_OPCODES:
            try:
                hex_script += '{:02x}'.format(ord(NAME_OPCODES[part]))
            except:
                raise Exception('Invalid opcode: {}'.format(part))
        elif part.startswith('0x'):
            # literal hex string
            hex_script += part[2:]
        elif is_valid_int(part):
            hex_part = '{:02x}'.format(int(part))
            if len(hex_part) % 2 != 0:
                hex_part = '0' + hex_part
            hex_script += hex_part
        elif is_hex(part) and len(part) % 2 == 0:
            hex_script += part
        else:
            raise ValueError(
                'Invalid script (at {}), contains invalid characters: {}'.
                format(part, script))

    if len(hex_script) % 2 != 0:
        raise ValueError(
            'Invalid script: must have an even number of chars (got {}).'.
            format(hex_script))

    return hex_script
Esempio n. 12
0
def broadcast(message_hash, private_key, blockchain_client, testset=False, blockchain_broadcaster=None, user_public_key=None, tx_only=False):
    
    # sanity check 
    pay_fee = True
    if user_public_key is not None:
        pay_fee = False
        tx_only = True

    if user_public_key is None and private_key is None:
        raise Exception("Missing both public and private key")
    
    if not tx_only and private_key is None:
        raise Exception("Need private key for broadcasting")
    
    if len(message_hash) != 40:
        raise Exception("Invalid message hash: not 20 bytes")

    if not is_hex( message_hash ):
        raise Exception("Invalid message hash: not hex")

    if blockchain_broadcaster is None:
        blockchain_broadcaster = blockchain_client 
    
    from_address = None 
    inputs = None
    private_key_obj = None
    
    if user_public_key is not None:
        # subsidizing 
        pubk = BitcoinPublicKey( user_public_key )

        from_address = pubk.address()
        inputs = get_unspents( from_address, blockchain_client )

    elif private_key is not None:
        # ordering directly 
        pubk = BitcoinPrivateKey( private_key ).public_key()
        public_key = pubk.to_hex()
        
        private_key_obj, from_address, inputs = analyze_private_key(private_key, blockchain_client)
         
    nulldata = build(message_hash, testset=testset)
    outputs = make_outputs( nulldata, inputs, from_address, pay_fee=pay_fee )
   
    if tx_only:
       
        unsigned_tx = serialize_transaction( inputs, outputs )
        return {'unsigned_tx': unsigned_tx}

    else:
       
        signed_tx = tx_serialize_and_sign( inputs, outputs, private_key_obj )
        response = broadcast_transaction( signed_tx, blockchain_broadcaster )
        response.update({'data': nulldata})
        return response
Esempio n. 13
0
def serialize_input(input, signature_script_hex=''):
    """ Serializes a transaction input.
    """
    if not (isinstance(input, dict) and 'transaction_hash' in input \
            and 'output_index' in input):
        raise Exception('Required parameters: transaction_hash, output_index')

    if is_hex(str(input['transaction_hash'])) and len(str(input['transaction_hash'])) != 64:
        raise Exception("Transaction hash '%s' must be 32 bytes" % input['transaction_hash'])

    elif not is_hex(str(input['transaction_hash'])) and len(str(input['transaction_hash'])) != 32:
        raise Exception("Transaction hash '%s' must be 32 bytes" % hexlify(input['transaction_hash']))

    if not 'sequence' in input:
        input['sequence'] = UINT_MAX

    return ''.join([
        flip_endian(input['transaction_hash']),
        hexlify(struct.pack('<I', input['output_index'])),
        hexlify(variable_length_int(len(signature_script_hex)/2)),
        signature_script_hex,
        hexlify(struct.pack('<I', input['sequence']))
    ])
Esempio n. 14
0
def parse(bin_payload):
    """
    Interpret a block's nulldata back into a SHA256.  The first three bytes (2 magic + 1 opcode)
    will not be present in bin_payload.
    """

    message_hash = hexlify(bin_payload)
    if not is_hex(message_hash):
        log.error("Not a message hash")
        return None

    if len(message_hash) != 40:
        log.error("Not a 160-bit hash")
        return None

    return {'opcode': 'ANNOUNCE', 'message_hash': message_hash}
Esempio n. 15
0
def load_signing_key(signing_key, crypto_backend=default_backend()):
    """ Optional: crypto backend object from the "cryptography" python library
    """
    if not isinstance(crypto_backend, (Backend, MultiBackend)):
        raise ValueError('backend must be a valid Backend object')

    if isinstance(signing_key, EllipticCurvePrivateKey):
        return signing_key
    elif isinstance(signing_key, (str, unicode)):
        invalid_strings = [b'-----BEGIN PUBLIC KEY-----']
        invalid_string_matches = [
            string_value in signing_key for string_value in invalid_strings
        ]
        if any(invalid_string_matches):
            raise ValueError(
                'Signing key must be a private key, not a public key.')

        if is_hex(signing_key):
            try:
                private_key_pem = ECPrivateKey(signing_key).to_pem()
            except:
                pass
            else:
                try:
                    return load_pem_private_key(private_key_pem,
                                                password=None,
                                                backend=crypto_backend)
                except:
                    raise InvalidPrivateKeyError()

            try:
                return load_der_private_key(signing_key,
                                            password=None,
                                            backend=crypto_backend)
            except Exception as e:
                traceback.print_exc()
                raise InvalidPrivateKeyError()
        else:
            try:
                return load_pem_private_key(signing_key,
                                            password=None,
                                            backend=crypto_backend)
            except:
                raise InvalidPrivateKeyError()
    else:
        raise ValueError('Signing key must be in string or unicode format.')
Esempio n. 16
0
def make_op_return_script(data, format='bin'):
    """ Takes in raw ascii data to be embedded and returns a script.
    """
    if format == 'hex':
        assert(is_hex(data))
        hex_data = data
    elif format == 'bin':
        hex_data = hexlify(data)
    else:
        raise Exception("Format must be either 'hex' or 'bin'")

    num_bytes = count_bytes(hex_data)
    if num_bytes > MAX_BYTES_AFTER_OP_RETURN:
        raise Exception('Data is %i bytes - must not exceed 40.' % num_bytes)

    script_string = 'OP_RETURN %s' % hex_data
    return script_to_hex(script_string)
Esempio n. 17
0
def make_op_return_script(data, format='bin'):
    """ Takes in raw ascii data to be embedded and returns a script.
    """
    if format == 'hex':
        assert (is_hex(data))
        hex_data = data
    elif format == 'bin':
        hex_data = hexlify(data)
    else:
        raise Exception("Format must be either 'hex' or 'bin'")

    num_bytes = count_bytes(hex_data)
    if num_bytes > MAX_BYTES_AFTER_OP_RETURN:
        raise Exception('Data is %i bytes - must not exceed 40.' % num_bytes)

    script_string = 'OP_RETURN %s' % hex_data
    return script_to_hex(script_string)
Esempio n. 18
0
def build(name, data_hash=None, data=None, testset=False):
    """ Takes in the name to update the data for and the data update itself.
    """
    hex_name = b40_to_hex(name)
    name_len = len(hex_name) / 2

    if not data_hash:
        if not data:
            raise ValueError('A data hash or data string is required.')
        data_hash = hex_hash160(data)
    elif not (is_hex(data_hash) and len(data_hash) == 40):
        raise ValueError('Data hash must be a 20 byte hex string.')

    readable_script = 'NAME_UPDATE %i %s %s' % (name_len, hex_name, data_hash)
    hex_script = name_script_to_hex(readable_script)
    packaged_script = add_magic_bytes(hex_script, testset=testset)

    return packaged_script
Esempio n. 19
0
def build(name, data_hash=None, data=None, testset=False):
    """ Takes in the name to update the data for and the data update itself.
    """
    hex_name = b40_to_hex(name)
    name_len = len(hex_name)/2

    if not data_hash:
        if not data:
            raise ValueError('A data hash or data string is required.')
        data_hash = hex_hash160(data)
    elif not (is_hex(data_hash) and len(data_hash) == 40):
        raise ValueError('Data hash must be a 20 byte hex string.')

    readable_script = 'NAME_UPDATE %i %s %s' % (name_len, hex_name, data_hash)
    hex_script = name_script_to_hex(readable_script)
    packaged_script = add_magic_bytes(hex_script, testset=testset)

    return packaged_script
Esempio n. 20
0
def update_sanity_test( name, consensus_hash, data_hash ):
    """
    Verify the validity of an update's data

    Return True if valid
    Raise exception if not
    """
    
    if name is not None and (not is_b40( name ) or "+" in name or name.count(".") > 1):
       raise Exception("Name '%s' has non-base-38 characters" % name)
   
    if data_hash is not None and not is_hex( data_hash ):
       raise Exception("Invalid hex string '%s': not hex" % (data_hash))
    
    if len(data_hash) != 2 * LENGTH_VALUE_HASH:
       raise Exception("Invalid hex string '%s': bad length" % (data_hash))

    return True
Esempio n. 21
0
def update_sanity_test( name, consensus_hash, data_hash ):
    """
    Verify the validity of an update's data

    Return True if valid
    Raise exception if not
    """
    
    if name is not None and (not is_b40( name ) or "+" in name or name.count(".") > 1):
       raise Exception("Name '%s' has non-base-38 characters" % name)
   
    if data_hash is not None and not is_hex( data_hash ):
       raise Exception("Invalid hex string '%s': not hex" % (data_hash))
    
    if len(data_hash) != 2 * LENGTHS['update_hash']:
       raise Exception("Invalid hex string '%s': bad length" % (data_hash))

    return True
Esempio n. 22
0
def parse(bin_payload):    
    """
    Interpret a block's nulldata back into a SHA256.  The first three bytes (2 magic + 1 opcode)
    will not be present in bin_payload.
    """
    
    message_hash = hexlify(bin_payload)
    if not is_hex( message_hash ):
        log.error("Not a message hash")
        return None 

    if len(message_hash) != 40:
        log.error("Not a 160-bit hash")
        return None 

    return {
       'opcode': 'ANNOUNCE',
       'message_hash': message_hash
    }
Esempio n. 23
0
def script_to_hex(script):
    """ Parse the string representation of a script and return the hex version.
        Example: "OP_DUP OP_HASH160 c629...a6db OP_EQUALVERIFY OP_CHECKSIG"
    """
    hex_script = ''
    parts = script.split(' ')
    for part in parts:
        if part[0:3] == 'OP_':
            try:
                hex_script += '%0.2x' % eval(part)
            except:
                raise Exception('Invalid opcode: %s' % part)
        elif isinstance(part, (int)):
            hex_script += '%0.2x' % part
        elif is_hex(part):
            hex_script += '%0.2x' % count_bytes(part) + part
        else:
            raise Exception('Invalid script - only opcodes and hex characters allowed.')
    return hex_script
Esempio n. 24
0
def script_to_hex(script):
    """ Parse the string representation of a script and return the hex version.
        Example: "OP_DUP OP_HASH160 c629...a6db OP_EQUALVERIFY OP_CHECKSIG"
    """
    hex_script = ''
    parts = script.split(' ')
    for part in parts:
        if part[0:3] == 'OP_':
            try:
                hex_script += '%0.2x' % eval(part)
            except:
                raise Exception('Invalid opcode: %s' % part)
        elif isinstance(part, (int)):
            hex_script += '%0.2x' % part
        elif is_hex(part):
            hex_script += '%0.2x' % count_bytes(part) + part
        else:
            raise Exception(
                'Invalid script - only opcodes and hex characters allowed.')
    return hex_script
Esempio n. 25
0
def make_transaction(message_hash, payment_addr, blockchain_client, tx_fee=0):
    
    message_hash = str(message_hash)
    payment_addr = str(payment_addr)
    tx_fee = int(tx_fee)

    # sanity check 
    if len(message_hash) != 40:
        raise Exception("Invalid message hash: not 20 bytes")

    if not is_hex( message_hash ):
        raise Exception("Invalid message hash: not hex")
    
    inputs = None
    private_key_obj = None
    
    inputs = get_unspents( payment_addr, blockchain_client )
    nulldata = build(message_hash)
    outputs = make_outputs( nulldata, inputs, payment_addr, tx_fee )
   
    return (inputs, outputs)
    def parse_transaction(self, block_id, tx):
        """
        Given a block ID and OP_RETURN transaction, try to parse it into a virtual chain operation
        """

        op_return_hex = tx['nulldata']
        inputs = tx['vin']
        outputs = tx['vout']
        senders = tx['senders']

        if not is_hex(op_return_hex):
            return None

        if len(op_return_hex) % 2 != 0:
            return None

        try:
            op_return_bin = binascii.unhexlify(op_return_hex)
        except Exception, e:
            log.error("Failed to parse transaction: %s (OP_RETUAN= %s)" % (tx, op_return_hex))
            raise e
Esempio n. 27
0
def name_script_to_hex(script):
    """ Parse the readable version of a name script, return the hex version.
    """
    hex_script = ''
    parts = script.split(' ')
    for part in parts:
        if part[0:5] == 'NAME_':
            try:
                hex_script += '%0.2x' % ord(eval(part))
            except:
                raise Exception('Invalid opcode: %s' % part)
        elif is_hex(part) and len(part) % 2 == 0:
            hex_script += part
        elif is_valid_int(part):
            hex_script += '%0.2x' % int(part)
        else:
            raise ValueError(
                'Invalid script, contains invalid characters: %s' % script)
    if len(hex_script) % 2 != 0:
        raise ValueError('Invalid script: must have an even number of chars.')
    return hex_script
Esempio n. 28
0
def build(message_hash, testset=False):
    """
     
    Record format:
    
    0    2  3                             23
    |----|--|-----------------------------|
    magic op   message hash (160-bit)
    
    """
   
    if len(message_hash) != 40:
        raise Exception("Invalid hash: not 20 bytes")

    if not is_hex(message_hash):
        raise Exception("Invalid hash: not hex")

    readable_script = "ANNOUNCE 0x%s" % (message_hash)
    hex_script = blockstore_script_to_hex(readable_script)
    packaged_script = add_magic_bytes(hex_script, testset=testset)
    
    return packaged_script 
Esempio n. 29
0
def build(message_hash, testset=False):
    """
     
    Record format:
    
    0    2  3                             23
    |----|--|-----------------------------|
    magic op   message hash (160-bit)
    
    """

    if len(message_hash) != 40:
        raise Exception("Invalid hash: not 20 bytes")

    if not is_hex(message_hash):
        raise Exception("Invalid hash: not hex")

    readable_script = "ANNOUNCE 0x%s" % (message_hash)
    hex_script = blockstore_script_to_hex(readable_script)
    packaged_script = add_magic_bytes(hex_script, testset=testset)

    return packaged_script
Esempio n. 30
0
    def parse_transaction(self, block_id, tx):
        """
        Given a block ID and an OP_RETURN transaction, 
        try to parse it into a virtual chain operation.
        
        Use the implementation's 'db_parse' method to do so.
        
        Set the following fields in op:
        * virtualchain_opcode:   the operation code 
        * virtualchain_outputs:  the list of transaction outputs
        * virtualchain_senders:  the list of transaction senders 
        * virtualchain_fee:      the total amount of money sent
        * virtualchain_block_number:  the block ID in which this transaction occurred
        
        Return a dict representing the data on success.
        Return None on error
        """

        op_return_hex = tx['nulldata']
        inputs = tx['vin']
        outputs = tx['vout']
        senders = tx['senders']
        fee = tx['fee']

        if not is_hex(op_return_hex):
            # not a valid hex string
            return None

        if len(op_return_hex) % 2 != 0:
            # not valid hex string
            return None

        try:
            op_return_bin = binascii.unhexlify(op_return_hex)
        except Exception, e:
            log.error("Failed to parse transaction: %s (OP_RETURN = %s)" %
                      (tx, op_return_hex))
            raise e
Esempio n. 31
0
 def parse_transaction( self, block_id, tx ):
     """
     Given a block ID and an OP_RETURN transaction, 
     try to parse it into a virtual chain operation.
     
     Use the implementation's 'db_parse' method to do so.
     
     Set the following fields in op:
     * virtualchain_opcode:   the operation code 
     * virtualchain_outputs:  the list of transaction outputs
     * virtualchain_senders:  the list of transaction senders 
     * virtualchain_fee:      the total amount of money sent
     * virtualchain_block_number:  the block ID in which this transaction occurred
     
     Return a dict representing the data on success.
     Return None on error
     """
     
     op_return_hex = tx['nulldata']
     inputs = tx['vin']
     outputs = tx['vout']
     senders = tx['senders']
     fee = tx['fee']
     
     if not is_hex(op_return_hex):
         # not a valid hex string 
         return None
     
     if len(op_return_hex) % 2 != 0:
         # not valid hex string 
         return None
     
     try:
         op_return_bin = binascii.unhexlify( op_return_hex )
     except Exception, e:
         log.error("Failed to parse transaction: %s (OP_RETURN = %s)" % (tx, op_return_hex))
         raise e
def make_transaction(message_hash, payment_addr, blockchain_client, tx_fee=0, subsidize=False, safety=True):
    
    message_hash = str(message_hash)
    payment_addr = str(payment_addr)
    tx_fee = int(tx_fee)

    # sanity check 
    if len(message_hash) != 40:
        raise Exception("Invalid message hash: not 20 bytes")

    if not is_hex( message_hash ):
        raise Exception("Invalid message hash: not hex")
    
    inputs = None
    private_key_obj = None
    
    inputs = tx_get_unspents( payment_addr, blockchain_client )
    if safety:
        assert len(inputs) > 0

    nulldata = build(message_hash)
    outputs = make_outputs( nulldata, inputs, payment_addr, tx_fee, pay_fee=(not subsidize) )
   
    return (inputs, outputs)
Esempio n. 33
0
def bin_hash160(s, hex_format=False):
    """ s is in hex or binary format
    """
    if hex_format and is_hex(s):
        s = unhexlify(s)
    return hashlib.new('ripemd160', bin_sha256(s)).digest()
Esempio n. 34
0
def is_256bit_hex_string(val):
    return (isinstance(val, str) and len(val) == 64 and is_hex(val))
Esempio n. 35
0
def hex_hash160(s, hex_format=False):
    """ s is in hex or binary format
    """
    if hex_format and is_hex(s):
        s = unhexlify(s)
    return hexlify(bin_hash160(s))
Esempio n. 36
0
def bin_hash160(s, hex_format=False):
    """ s is in hex or binary format
    """
    if hex_format and is_hex(s):
        s = unhexlify(s)
    return hashlib.new('ripemd160', bin_sha256(s)).digest()
Esempio n. 37
0
def count_bytes(hex_s):
    """ Calculate the number of bytes of a given hex string.
    """
    assert(is_hex(hex_s))
    return len(hex_s)/2
Esempio n. 38
0
def snv_lookup(verify_name,
               verify_block_id,
               trusted_serial_number_or_txid_or_consensus_hash,
               proxy=None,
               trusted_txid=None):
    """
    High-level call to simple name verification:
    Given a trusted serial number, txid, or consensus_hash, use it as a trust root to verify that
    a previously-registered but untrusted name (@verify_name) exists and was processed
    at a given block (@verify_block_id)

    Basically, use the trust root to derive a "current" block ID and consensus hash, and
    use the untrusted (name, block_id) pair to derive an earlier untrusted block ID and
    consensus hash.  Then, use the snv_get_nameops_at() method to verify that the name
    existed at the given block ID.

    The Blockstack node is not trusted.  This algorithm prevents a malicious Blockstack node
    from getting the caller to falsely trust @verify_name and @verify_block_id by
    using SNV to confirm that:
    * the consensus hash at the trust root's block is consistent with @verify_name's
    corresponding NAMESPACE_PREORDER or NAME_PREORDER;
    * the consensus hash at @trusted_serial_number's block is consistent with @verify_name's
    consensus hash (from @verify_serial_number)

    The only way a Blockstack node working with a malicious Sybil can trick the caller is if
    both can create a parallel history of name operations such that the final consensus hash
    at @trusted_serial_number's block collides.  This is necessary, since the client uses
    the hash over a block's operations and prior consensus hashes to transitively trust
    prior consensus hashes--if the later consensus hash is assumed out-of-band to be valid,
    then the transitive closure of all prior consensus hashes will be assumed valid as well.
    This means that the only way to drive the valid consensus hash from a prior invalid
    consensus hash is to force a hash collision somewhere in the transitive closure, which is infeasible.

    NOTE: @trusted_txid is needed for isolating multiple operations in the same name within a single block.

    Return the list of nameops in the given verify_block_id that match.
    """

    proxy = get_default_proxy() if proxy is None else proxy

    trusted_serial_number_or_txid_or_consensus_hash = str(
        trusted_serial_number_or_txid_or_consensus_hash)

    bitcoind_proxy = get_bitcoind_client(config_path=proxy.conf['path'])
    trusted_serial_number = None
    trusted_tx_index = None
    trusted_consensus_hash = None
    trusted_block_id = None

    # what did we get?
    hash_len_64 = len(trusted_serial_number_or_txid_or_consensus_hash) == 64
    hash_len_32 = len(trusted_serial_number_or_txid_or_consensus_hash) == 32
    hash_parts_2 = len(
        trusted_serial_number_or_txid_or_consensus_hash.split('-')) == 2
    hash_is_hex = is_hex(trusted_serial_number_or_txid_or_consensus_hash)

    if hash_len_64 and hash_is_hex:
        # txid: convert to trusted block ID and consensus hash
        trusted_txid = trusted_serial_number_or_txid_or_consensus_hash
        trusted_block_hash, trusted_block_data, trusted_tx = txid_to_block_data(
            trusted_txid, bitcoind_proxy)
        if trusted_block_hash is None or trusted_block_data is None or trusted_tx is None:
            return {'error': 'Unable to look up given transaction ID'}

        # must have a consensus hash
        # TOOD: Check why return values are ignored
        op, payload = parse_tx_op_return(trusted_tx)
        trusted_consensus_hash = get_consensus_hash_from_tx(trusted_tx)
        if trusted_consensus_hash is None:
            return {
                'error': 'Tx does not refer to a consensus-bearing transaction'
            }

        # find the block for this consensus hash (it's not the same as the serial number's block ID,
        # but that's okay--if the consensus hash in this tx is inauthentic, it will be unreachable
        # from the other consensus hash [short of a SHA256 collision])
        trusted_block_id = get_block_from_consensus(trusted_consensus_hash,
                                                    proxy=proxy)
    elif hash_len_32 and hash_is_hex:
        # consensus hash
        trusted_consensus_hash = trusted_serial_number_or_txid_or_consensus_hash
        trusted_block_id = get_block_from_consensus(trusted_consensus_hash,
                                                    proxy=proxy)
        if isinstance(trusted_block_id, dict) and 'error' in trusted_block_id:
            # got error back
            return trusted_block_id
    elif hash_parts_2:
        # must be a serial number
        parts = trusted_serial_number_or_txid_or_consensus_hash.split('-')
        try:
            trusted_block_id = int(parts[0])
            # TODO: Check why this variable is unused
            trusted_tx_index = int(parts[1])
        except:
            log.error('Malformed serial number "{}"'.format(
                trusted_serial_number_or_txid_or_consensus_hash))
            return {'error': 'Did not receive a valid serial number'}

        trusted_tx = serial_number_to_tx(
            trusted_serial_number_or_txid_or_consensus_hash, bitcoind_proxy)
        if trusted_tx is None:
            return {
                'error':
                'Unable to convert given serial number into transaction'
            }

        # tx must have a consensus hash
        # TOOD: Check why return values are ignored
        op, payload = parse_tx_op_return(trusted_tx)
        trusted_consensus_hash = get_consensus_hash_from_tx(trusted_tx)
        if trusted_consensus_hash is None:
            return {
                'error': 'Tx does not refer to a consensus-bearing transaction'
            }

        # find the block for this consensus hash (it's not the same as the serial number's block ID,
        # but that's okay--if the consensus hash in this tx is inauthentic, it will be unreachable
        # from the other consensus hash [short of a SHA256 collision])
        trusted_block_id = get_block_from_consensus(trusted_consensus_hash,
                                                    proxy=proxy)
        if isinstance(trusted_block_id, dict) and 'error' in trusted_block_id:
            # got error back
            return trusted_block_id
    else:
        msg = 'Did not receive a valid txid, consensus hash, or serial number ({})'
        return {
            'error':
            msg.format(trusted_serial_number_or_txid_or_consensus_hash)
        }

    if trusted_block_id < verify_block_id:
        msg = 'Trusted block/consensus hash came before the untrusted block/consensus hash'
        return {'error': msg}

    # go verify the name
    verify_consensus_hash = get_consensus_at(verify_block_id, proxy=proxy)
    historic_namerecs = snv_name_verify(verify_name,
                                        trusted_block_id,
                                        trusted_consensus_hash,
                                        verify_block_id,
                                        verify_consensus_hash,
                                        trusted_txid=trusted_txid,
                                        trusted_txindex=trusted_tx_index)

    if 'error' in historic_namerecs:
        return historic_namerecs

    return historic_namerecs['nameops']
Esempio n. 39
0
def is_hex_ecdsa_pubkey(val):
    return (is_hex(val) and len(val) == 128)
Esempio n. 40
0
 def test_is_hex_with_64bit_string(self):
     s = "d9fa02e46cd3867f51279dfae592d3706022ee93c175b49c30c8c962722fc890"
     self.assertTrue(is_hex(s))
Esempio n. 41
0
 def test_charset_to_hex(self):
     s = ("9859361987058468004536324485715460737416376519236217359320056"
          "4555477131708560")
     s2 = charset_to_hex(s, string.digits)
     self.assertTrue(is_hex(s2))
Esempio n. 42
0
def snv_lookup(verify_name, verify_block_id, trusted_serial_number_or_txid_or_consensus_hash, proxy=None):
    """
    High-level call to simple name verification:
    Given a trusted serial number, txid, or consensus_hash, use it as a trust root to verify that
    a previously-registered but untrusted name (@verify_name) exists and was processed
    at a given block (@verify_block_id)

    Basically, use the trust root to derive a "current" block ID and consensus hash, and
    use the untrusted (name, block_id) pair to derive an earlier untrusted block ID and
    consensus hash.  Then, use the snv_get_nameops_at() method to verify that the name
    existed at the given block ID.

    The Blockstack node is not trusted.  This algorithm prevents a malicious Blockstack node
    from getting the caller to falsely trust @verify_name and @verify_block_id by
    using SNV to confirm that:
    * the consensus hash at the trust root's block is consistent with @verify_name's
    corresponding NAMESPACE_PREORDER or NAME_PREORDER;
    * the consensus hash at @trusted_serial_number's block is consistent with @verify_name's
    consensus hash (from @verify_serial_number)

    The only way a Blockstack node working with a malicious Sybil can trick the caller is if
    both can create a parallel history of name operations such that the final consensus hash
    at @trusted_serial_number's block collides.  This is necessary, since the client uses
    the hash over a block's operations and prior consensus hashes to transitively trust
    prior consensus hashes--if the later consensus hash is assumed out-of-band to be valid,
    then the transitive closure of all prior consensus hashes will be assumed valid as well.
    This means that the only way to drive the valid consensus hash from a prior invalid
    consensus hash is to force a hash collision somewhere in the transitive closure, which is infeasible.
    """

    if proxy is None:
        proxy = get_default_proxy()

    trusted_serial_number_or_txid_or_consensus_hash = str(trusted_serial_number_or_txid_or_consensus_hash)

    bitcoind_proxy = get_bitcoind_client( config_path=proxy.conf['path'] )
    trusted_serial_number = None
    trusted_txid = None
    trusted_consensus_hash = None
    trusted_block_id = None

    # what did we get?
    if len(trusted_serial_number_or_txid_or_consensus_hash) == 64 and is_hex(trusted_serial_number_or_txid_or_consensus_hash):
        # txid: convert to trusted block ID and consensus hash
        trusted_txid = trusted_serial_number_or_txid_or_consensus_hash
        trusted_block_hash, trusted_block_data, trusted_tx = txid_to_block_data(trusted_txid, bitcoind_proxy)
        if trusted_block_hash is None or trusted_block_data is None or trusted_tx is None:
            return {'error': 'Unable to look up given transaction ID'}

        # must have a consensus hash
        op, payload = parse_tx_op_return(trusted_tx)
        trusted_consensus_hash = get_consensus_hash_from_tx(trusted_tx)
        if trusted_consensus_hash is None:
            return {'error': 'Tx does not refer to a consensus-bearing transaction'}

        # find the block for this consensus hash (it's not the same as the serial number's block ID,
        # but that's okay--if the consensus hash in this tx is inauthentic, it will be unreachable
        # from the other consensus hash [short of a SHA256 collision])
        trusted_block_id = get_block_from_consensus(trusted_consensus_hash, proxy=proxy)


    elif len(trusted_serial_number_or_txid_or_consensus_hash) == 32 and is_hex(trusted_serial_number_or_txid_or_consensus_hash):
        # consensus hash
        trusted_consensus_hash = trusted_serial_number_or_txid_or_consensus_hash
        trusted_block_id = get_block_from_consensus(trusted_consensus_hash, proxy=proxy)
        if type(trusted_block_id) == dict and 'error' in trusted_block_id:
            # got error back
            return trusted_block_id


    elif len(trusted_serial_number_or_txid_or_consensus_hash.split("-")) == 2:
        # must be a serial number
        parts = trusted_serial_number_or_txid_or_consensus_hash.split("-")
        try:
            trusted_block_id = int(parts[0])
            trusted_tx_index = int(parts[1])
        except:
            log.error("Malformed serial number '%s'" % trusted_serial_number_or_txid_or_consensus_hash)
            return {'error': 'Did not receive a valid serial number'}

        trusted_tx = serial_number_to_tx(trusted_serial_number_or_txid_or_consensus_hash, bitcoind_proxy)
        if trusted_tx is None:
            return {'error': 'Unable to convert given serial number into transaction'}

        # tx must have a consensus hash
        op, payload = parse_tx_op_return(trusted_tx)
        trusted_consensus_hash = get_consensus_hash_from_tx(trusted_tx)
        if trusted_consensus_hash is None:
            return {'error': 'Tx does not refer to a consensus-bearing transaction'}

        # find the block for this consensus hash (it's not the same as the serial number's block ID,
        # but that's okay--if the consensus hash in this tx is inauthentic, it will be unreachable
        # from the other consensus hash [short of a SHA256 collision])
        trusted_block_id = get_block_from_consensus(trusted_consensus_hash, proxy=proxy)
        if type(trusted_block_id) == dict and 'error' in trusted_block_id:
            # got error back
            return trusted_block_id

    else:
        return {'error': 'Did not receive a valid txid, consensus hash, or serial number (%s)' % trusted_serial_number_or_txid_or_consensus_hash}

    if trusted_block_id < verify_block_id:
        return {'error': 'Trusted block/consensus hash came before the untrusted block/consensus hash'}

    # go verify the name
    verify_consensus_hash = get_consensus_at(verify_block_id, proxy=proxy)
    historic_namerec = snv_name_verify(verify_name, trusted_block_id, trusted_consensus_hash, verify_block_id, verify_consensus_hash)

    return historic_namerec
Esempio n. 43
0
def is_256bit_hex_string(val):
    return isinstance(val, str) and len(val) == 64 and is_hex(val)
Esempio n. 44
0
def is_hex_ecdsa_pubkey(val):
    return is_hex(val) and len(val) == 128
Esempio n. 45
0
def count_bytes(hex_s):
    """ Calculate the number of bytes of a given hex string.
    """
    assert(is_hex(hex_s))
    return len(hex_s)/2
Esempio n. 46
0
def hex_hash160(s, hex_format=False):
    """ s is in hex or binary format
    """
    if hex_format and is_hex(s):
        s = unhexlify(s)
    return hexlify(bin_hash160(s))