def add_tx(self, tx): if not isinstance(tx, dict): return False address = tools.tx_owner_address(tx) # tools.log('attempt to add tx: ' +str(tx)) txs_in_pool = self.tx_pool() response = Response(True, None) if 'type' not in tx or not isinstance(tx['type'], str) \ or tx['type'] not in BlockchainService.tx_types: response.setData('type error') response.setFlag(False) if tx in txs_in_pool: response.setData('no duplicates') response.setFlag(False) if not BlockchainService.tx_integrity_check(tx).getFlag(): response.setData('tx: ' + str(tx)) response.setFlag(False) if tx['count'] != self.account.known_tx_count( tools.tx_owner_address(tx)): response.setData('count error') response.setFlag(False) if not self.account.is_tx_affordable(address, tx): response.setData('fee check error') response.setFlag(False) if response.getFlag(): self.tx_pool_add(tx) return 'added tx into the pool: ' + str(tx) else: return 'failed to add tx because: ' + response.getData()
def update_account_with_txs(self, address, account, txs, add_flag=True, only_outgoing=False): def apply(a, b): if isinstance(a, int): if add_flag: a += b else: a -= b elif isinstance(a, list): if add_flag: a.append(b) else: a.remove(b) return a for tx in txs: owner = tools.tx_owner_address(tx) if tx['type'] == 'spend': if owner == address: account['amount'] = apply(account['amount'], -tx['amount']) account['count'] = apply(account['count'], 1) elif tx['to'] == address and not only_outgoing: account['amount'] = apply(account['amount'], tx['amount']) return account
def update_database_with_tx(self, tx, block_length, count_pool=False): send_address = tools.tx_owner_address(tx) send_account = self.get_account(send_address) if tx['type'] == 'mint': send_account['amount'] += tools.block_reward(block_length) self.update_account(send_address, send_account) elif tx['type'] == 'spend': if tx['count'] != self.known_tx_count(send_address, count_pool=count_pool): return False recv_address = tx['to'] recv_account = self.get_account(recv_address) send_account['amount'] -= tx['amount'] send_account['count'] += 1 send_account['tx_blocks'].append(block_length) recv_account['amount'] += tx['amount'] recv_account['tx_blocks'].append(block_length) if (recv_account['amount'] < 0) or (send_account['amount'] < 0): return False self.update_account(send_address, send_account) self.update_account(recv_address, recv_account) else: return False return True
def tx_integrity_check(tx): """ This functions test whether a transaction has basic things right. Does it have amount, recipient, RIGHT SIGNATURES and correct address types. :param tx: :return: """ if not isinstance(tx, dict): return Response(False, 'Transaction is not a proper python dict') if tx['version'] != custom.version: return Response(False, 'belongs to an earlier version') if tx['type'] == 'spend': if 'to' not in tx or not isinstance(tx['to'], str): return Response( False, 'Reward or spend transactions must be addressed') if not BlockchainService.tx_signature_check(tx): return Response(False, 'Transaction is not properly signed') if not tools.is_address_valid(tx['to']): return Response(False, 'Address is not valid') if tx['to'] == tools.tx_owner_address(tx): return Response(False, 'You cannot transfer money to same account!') if 'amount' not in tx or not isinstance(tx['amount'], int): return Response( False, 'Transaction amount is not given or not a proper integer') if 'count' not in tx or not isinstance(tx['count'], int): return Response(False, 'transaction count is missing') return Response(True, 'Everything seems fine')
def rollback_block(self, block): # TODO: 0.007-12c changes """ A block rollback means removing the block from chain. A block is defined by its transactions. Here we rollback every object in database to the version that existed before this block. Blocks must be removed one by one. :param block: Block to be removed :return: Success of removal """ current_length = self.db.get('length') if block['length'] != current_length: # Block is not at the top the chain return False for tx in block['txs']: tx_owner_address = tools.tx_owner_address(tx) owner_account = self.get_account(tx_owner_address) if tx['type'] == 'mint': owner_account['amount'] -= tools.block_reward(block['length']) self.db.put(tx_owner_address, owner_account) elif tx['type'] == 'spend': owner_account['amount'] += tx['amount'] owner_account['count'] -= 1 owner_account['tx_blocks'].remove(block['length']) receiver_account = self.db.get(tx['to']) receiver_account['amount'] -= tx['amount'] receiver_account['tx_blocks'].remove(block['length']) self.db.put(tx_owner_address, owner_account) self.db.put(tx['to'], receiver_account)
def history(): from halocoin.model.wallet import Wallet address = request.values.get('address', None) if address is None: default_wallet = engine.instance.clientdb.get_default_wallet() if default_wallet is not None: wallet_name = default_wallet['wallet_name'] password = default_wallet['password'] encrypted_wallet_content = engine.instance.clientdb.get_wallet( wallet_name) wallet = Wallet.from_string( tools.decrypt(password, encrypted_wallet_content)) address = wallet.address account = engine.instance.statedb.get_account(wallet.address) txs = {"send": [], "recv": []} for block_index in reversed(account['tx_blocks']): block = engine.instance.blockchain.get_block(block_index) for tx in block['txs']: if tx['type'] == 'mint': continue tx['block'] = block_index owner = tools.tx_owner_address(tx) if owner == address: txs['send'].append(tx) elif tx['type'] == 'spend' and tx['to'] == address: txs['recv'].append(tx) return generate_json_response(txs)
def mempool(): purge = request.values.get('purge', None) if purge is not None: engine.instance.blockchain.tx_pool_pop_all() pool = copy.deepcopy(engine.instance.blockchain.tx_pool()) for i, tx in enumerate(pool): pool[i]['from'] = tools.tx_owner_address(tx) return generate_json_response(pool)
def update_account_with_txs(address, account, txs): for tx in txs: owner = tools.tx_owner_address(tx) if tx['type'] == 'spend': if owner == address: account['amount'] -= tx['amount'] if tx['to'] == address: account['amount'] += tx['amount'] return account
def print_history(history): if history is None: print("Could not receive history") elif isinstance(history, str): print(history) else: for tx in history['send']: print("In Block {} {} => {} for amount {}".format( tx['block'], Colors.HEADER + tools.tx_owner_address(tx) + Colors.ENDC, Colors.WARNING + tx['to'] + Colors.ENDC, tx['amount'])) for tx in history['recv']: print("In Block {} {} => {} for amount {}".format( tx['block'], Colors.WARNING + tools.tx_owner_address(tx) + Colors.ENDC, Colors.HEADER + tx['to'] + Colors.ENDC, tx['amount'])) for tx in history['mine']: print("In Block {} {} mined amount {}".format( tx['block'], Colors.HEADER + tools.tx_owner_address(tx) + Colors.ENDC, tools.block_reward(tx['block'])))
def history(): address = request.values.get('address', None) if address is None: address = engine.instance.db.get('address') account = engine.instance.account.get_account(address) txs = {"send": [], "recv": [], "mine": []} for block_index in reversed(account['tx_blocks']): block = engine.instance.db.get(str(block_index)) for tx in block['txs']: tx['block'] = block_index owner = tools.tx_owner_address(tx) if owner == address: txs['send'].append(tx) elif tx['type'] == 'spend' and tx['to'] == address: txs['recv'].append(tx) for block_index in reversed(account['mined_blocks']): block = engine.instance.db.get(str(block_index)) for tx in block['txs']: tx['block'] = block_index owner = tools.tx_owner_address(tx) if owner == address: txs['mine'].append(tx) return generate_json_response(txs)
def print_txs(txs, length=-1): table = [] for tx in txs: tx['from'] = tools.tx_owner_address(tx) if tx['type'] == 'mint': tx['to'] = 'N/A' tx['amount'] = tools.block_reward(length) tx['message'] = '' table.append( [tx['type'], tx['from'], tx['to'], tx['amount'], tx['message']]) print( tabulate(table, headers=[ Colors.HEADER + 'Type' + Colors.ENDC, Colors.HEADER + 'From' + Colors.ENDC, Colors.HEADER + 'To' + Colors.ENDC, Colors.HEADER + 'Amount' + Colors.ENDC, Colors.HEADER + 'Message' + Colors.ENDC ], tablefmt='orgtbl'))
def block(): start = int(request.values.get('start', '-1')) end = int(request.values.get('end', '-1')) length = engine.instance.db.get('length') if start == -1 and end == -1: end = length start = max(end - 20, 0) elif start == -1: start = max(end - 20, 0) elif end == -1: end = min(length, start + 20) result = {"start": start, "end": end, "blocks": []} for i in range(start, end + 1): block = engine.instance.db.get(str(i)) if block is None: break mint_tx = list(filter(lambda t: t['type'] == 'mint', block['txs']))[0] block['miner'] = tools.tx_owner_address(mint_tx) result["blocks"].append(block) result["blocks"] = list(reversed(result["blocks"])) return generate_json_response(result)
def print_blocks(blocks): table = [] for block in blocks: if block['length'] == 0: block['prevHash'] = "N/A" block['time'] = datetime.datetime.fromtimestamp(int( block['time'])).strftime('%Y-%m-%d %H:%M:%S') mint_tx = list(filter(lambda t: t['type'] == 'mint', block['txs']))[0] table.append( [block['length'], tools.tx_owner_address(mint_tx), block['time']]) print(Colors.WARNING + "Blocks:\n" + Colors.ENDC) print( tabulate(table, headers=[ Colors.HEADER + 'Length' + Colors.ENDC, Colors.HEADER + 'Miner' + Colors.ENDC, Colors.HEADER + 'Time' + Colors.ENDC ], tablefmt='orgtbl')) if len(blocks) == 1: print(Colors.WARNING + "\nTransactions in the Block:\n" + Colors.ENDC) print_txs(blocks[0]['txs'], length=blocks[0]['length'])
def update_accounts_with_block(self, block, add_flag=True, simulate=False): """ :param block: :param add_flag: Is block being added or removed :param simulate: Do not actually update the accounts, return any irregularity :return: """ def apply(a, b): if isinstance(a, int): if add_flag: a += b else: a -= b elif isinstance(a, list): if add_flag: a.append(b) else: a.remove(b) return a def get_acc(address): if not simulate: account = self.get_account(address) else: if address not in account_sandbox: account = self.get_account(address) account_sandbox[address] = account account = account_sandbox[address] return account def update_acc(address, account): if not simulate: self.update_account(address, account) else: account_sandbox[address] = account return True flag = True account_sandbox = {} for tx in block['txs']: send_address = tools.tx_owner_address(tx) send_account = get_acc(send_address) if tx['type'] == 'mint': send_account['amount'] = apply( send_account['amount'], tools.block_reward(block['length'])) send_account['mined_blocks'] = apply( send_account['mined_blocks'], block['length']) elif tx['type'] == 'spend': recv_address = tx['to'] recv_account = get_acc(recv_address) send_account['amount'] = apply(send_account['amount'], -tx['amount']) send_account['count'] = apply(send_account['count'], 1) send_account['tx_blocks'] = apply(send_account['tx_blocks'], block['length']) recv_account['amount'] = apply(recv_account['amount'], tx['amount']) recv_account['tx_blocks'] = apply(recv_account['tx_blocks'], block['length']) flag &= (recv_account['amount'] >= 0) flag &= (send_account['amount'] >= 0) if not flag: return False else: update_acc(send_address, send_account) if tx['type'] == 'spend': update_acc(recv_address, recv_account) return flag
def number_of_unconfirmed_txs(_address): return len( list( filter(lambda t: _address == tools.tx_owner_address(t), txs_in_pool)))
def txs(): pool = engine.instance.blockchain.tx_pool() for i, tx in enumerate(pool): pool[i]['from'] = tools.tx_owner_address(tx) return generate_json_response(pool)