Ejemplo n.º 1
0
def sign_tx(tx: Transaction, idx: int, priv_key: str) -> Transaction:
    '''
    Signs the transaction

    Params:
        tx: Transaction object to be signed
        idx: Index of the vin to sign
        priv_key: private key used to prove that you authorized it
    '''
    # Make a copy so we don't overwrite the original object
    _tx = copy.deepcopy(tx)

    # When we're signing, null out all the vins
    # Except for ours when hashing
    vin = _tx.vins[idx]
    vouts = _tx.vouts
    txid = _tx.txid

    # Message for the signature is the hash of the transaction
    # with all vins nulled except for the one we're signing
    tx_hash = get_hash(vins=[vin], vouts=vouts, txids=[txid])

    pub_key = get_pub_key(priv_key)
    signature = sign_msg(tx_hash, priv_key)

    vin.signature = signature
    vin.pub_key = pub_key

    # Rebuild vins
    vins = _tx.vins
    vins[idx] = vin

    return Transaction(vins, vouts)
Ejemplo n.º 2
0
    def block_hash(self):
        # Don't use coinbase to calculate blockhash (since its appended)
        # after mining
        transactions = filter(lambda x: type(x) == Transaction,
                              self.transactions)
        txids = reduce(lambda x, y: x + [y.txid], transactions, [])
        vins = reduce(lambda x, y: x + y.vins, transactions, [])
        vouts = reduce(lambda x, y: x + y.vouts, transactions, [])

        return get_hash(vins=vins,
                        vouts=vouts,
                        txids=txids,
                        prev_block_hash=self.prev_block_hash,
                        height=self.height,
                        timestamp=self.timestamp,
                        difficulty=self.difficulty,
                        nonce=self.nonce)
Ejemplo n.º 3
0
def add_tx_to_block(tx: Transaction,
                    block: Block,
                    txs: Dict,
                    utxos: Dict) -> Tuple[Block, Dict, Dict]:
    '''
    Adds the tx to the to the blockchain and broadcasts it to
    connected nodes. 

    Updates and maintains the global cache of utxos. This is also used
    to check for double spending

    Params:
        tx: transaction to be added to the latest block
        block: latest block
        txs: Global dictionary of transactions (state of all txs)
        utxos: Global dictioanry of unspent transactions (contains
                the state of unspent txs)
    '''
    # Make copy of object
    _block = copy.deepcopy(block)
    _tx = copy.deepcopy(tx)
    _txs = copy.deepcopy(txs)
    _utxos = copy.deepcopy(utxos)

    # Can't send more than you received
    if (get_fees(_tx, _utxos) < 0):
        raise Exception('Attempting to spend more than you have!')

    # Update utxo cache
    # Whilst checking signature validity
    for idx, vout in enumerate(_tx.vouts):
        if _tx.txid not in _utxos:
            _utxos[_tx.txid] = {}

        _utxos[_tx.txid][idx] = {
            'address': vout.address,
            'amount': vout.amount,
            'spent': None
        }

    for vin in _tx.vins:
        if (vin.txid in _utxos) and (vin.index in _utxos[vin.txid]):
            if _utxos[vin.txid][vin.index]['spent'] is None:
                # Check if the address in the utxos[tx.txid] is the same as the public key
                # If it doesn't exist in the utxos, we're trying to double spend
                # If the vout address in the utxos doesn't match the private key
                # Then we're not authorized to spend this transaction

                # Check the signature
                try:
                    tx_hash = get_hash(
                        vins=[vin], vouts=_tx.vouts, txids=[_tx.txid])

                    same_address = get_address(
                        vin.pub_key) == _utxos[vin.txid][vin.index]['address']
                    valid_sig = is_sig_valid(
                        vin.signature, vin.pub_key, tx_hash)
                except:
                    raise Exception(
                        'Corrupted pub_key/signature for vin\n{}'.format(vin))

                if not (same_address and valid_sig):
                    raise Exception('You don\'t have the credentials to authorize this transaction:\n\t{}'.format(
                        vin
                    ))

                # Mark it as spent
                _utxos[vin.txid][vin.index]['spent'] = _tx.txid

            else:
                raise Exception(
                    'Transaction {} at vin {} has been spent'.format(vin.txid, vin.index))

        else:
            raise Exception('Transaction {} does not exist'.format(vin.txid))

    # Add to global_txs
    _txs[_tx.txid] = _tx

    # Wow state mutations
    _block.transactions = _block.transactions + [_tx]
    return _block, _txs, _utxos
Ejemplo n.º 4
0
 def txid(self):
     return get_hash(prev_block_hash=self.prev_block_hash,
                     reward_address=self.reward_address,
                     reward_amount=self.reward_amount)
Ejemplo n.º 5
0
 def txid(self):
     return get_hash(vins=self.vins, vouts=self.vouts)