def test_negative_locktime(): """ test for a negative locktime """ trns = make_synthetic_transaction(1) trns["locktime"] = -1 assert tx.validate_transaction(trns) == False
def test_invalid_vout_length(): """ test that the vout list length is not greater than the maximum allowed by the Helium config """ trn = make_synthetic_transaction(11) assert tx.validate_transaction(trn) == False
def test_missing_transactionid(): """ test missing transaction id """ trns = make_synthetic_transaction(1) del trns["transactionid"] assert tx.validate_transaction(trns) == False
def test_zero_version_number(): """ test zero version no """ trns = make_synthetic_transaction(1) trns["version"] = 0 assert tx.validate_transaction(trns) == False
def test_bad_transactionid(): """ test transaction id with an invalid length """ trns = make_synthetic_transaction(1) # replace the last char with an invalid char trns["transactionid"] = trns["transactionid"][:-1] + "z" assert tx.validate_transaction(trns) == False
def test_empty_scriptSig_pubkey(): """ test that ScriptSig public key field is not empty """ txn = make_synthetic_transaction(2) indices = randomize_list(txn['vin']) for ctr in list(range(len(indices))): txn['vin'][indices[ctr]]['ScriptSig'][1] = '' assert tx.validate_transaction(txn) == False
def test_negative_output_value(monkeypatch): """ test a negative transaction output value """ txn = make_synthetic_transaction(4) indices = randomize_list(txn['vout']) ctr = secrets.randbelow(len(indices)) monkeypatch.setitem(txn['vout'][indices[ctr]], 'value', -456712) assert tx.validate_transaction(txn) == False
def test_scriptpubkey_length_error(): """ test that ScriptPubKey list has a valid length """ txn = make_synthetic_transaction(4) indices = randomize_list(txn['vout']) for ctr in list(range(len(indices))): element = txn['vout'][indices[ctr]]['ScriptPubKey'][1] txn['vout'][indices[ctr]]['ScriptPubKey'].append(element) assert tx.validate_transaction(txn) == False
def test_no_prev_tx_reference(): """ test that the transaction's vin element has a reference to a previous transaction. """ txn = make_synthetic_transaction(1) indices = randomize_list(txn["vin"]) for ctr in list(range(len(indices))): txn['vin'][indices[ctr]]['txid'] = "" assert tx.validate_transaction(txn) == False
def test_invalid_txid_length(): """ test a previous transaction id for length """ txn = make_synthetic_transaction(2) id = rcrypt.make_uuid() id = "p" + id[0:] indices = randomize_list(txn['vin']) ctr = secrets.randbelow(len(indices)) txn['vin'][indices[ctr]]['txid'] = id assert tx.validate_transaction(txn) == False
def receive_transaction(transaction: "dictionary") -> "bool": # verify that the incoming transaction is valid if tx.validate_transaction(transaction) == False: logging.debug('receive_transaction: miner received an invalid transaction') return False # do not add the transaction if it already exists in the mempool for trans in mempool: if trans == transaction: return True # add the transaction to the mempool mempool.append(transaction) return True
def add_block(block: "dictionary") -> "bool": """ add_block: adds a block to the blockchain. Receives a block. The block attributes are checked for validity and each transaction in the block is tested for validity. If there are no errors, the block is written to a file as a sequence of raw bytes. Then the block is added to the blockchain. The chainstate database and the blk_index databases are updated. returns True if the block is added to the blockchain and False otherwise """ try: # validate the received block parameters if validate_block(block) == False: raise(ValueError("block validation error")) # validate the transactions in the block # update the chainstate database for trx in block['tx']: # first transaction in the block is a coinbase transaction if block["height"] == 0 or block['tx'][0] == trx: zero_inputs = True else: zero_inputs = False if tx.validate_transaction(trx, zero_inputs) == False: raise(ValueError("transaction validation error")) if hchaindb.transaction_update(trx) == False: raise(ValueError("chainstate update transaction error")) # serialize the block to a file if (serialize_block(block) == False): raise(ValueError("serialize block error")) # add the block to the blockchain in memory blockchain.append(block) # update the blk_index for transaction in block['tx']: blockindex.put_index(transaction["transactionid"], block["height"]) except Exception as err: print(str(err)) logging.debug('add_block: exception: ' + str(err)) return False return True
def receive_mined_block(block): # verify the proof of work if proof_of_work(block) == False: logging.debug("receive_mined_block: no proof of work") return False # Verify that the block is valid. Note that because of the False parameter # we are not validating the value of the block's previousblockhash value ret = bchain.validate_block(block, False) if ret == False: logging.debug('receive_mined_block: block is invalid') return False # validate transactions in the block for trans in block['tx']: if tx.validate_transaction(trans) == False: logging.debug("receive_mined_block: invalid transaction") return False # test if block is in the received_blocks list for blk in received_blocks: if blk == block: return False #test if block is in the primary or secondary blockchains if len(bchain.blockchain) > 0: if block == bchain.blockchain[-1]: return False if len(bchain.blockchain) > 1: if block == bchain.blockchain[-2]: return False if len(bchain.secondary_blockchain) > 0: if block == bchain.secondary_blockchain[-1]: return False if len(bchain.secondary_blockchain) > 1: if block == bchain.secondary_blockchain[-2]: return False # add the block to the blocks_received list received_blocks.append(block) return True
def receive_transaction(transaction: "dictionary") -> "bool": """ receives a transaction propagating over the P2P cryptocurrency network this function executes in a thread """ # do not add the transaction if: # it already exists in the mempool # it exists in the Chainstate # it is invalid try: # if the transaction is in the mempool, return for trans in mempool: if trans == transaction: return False # do not add the transaction if it has been accounted for in # the chainstate database. tx_fragment_id = transaction["transactionid"] + "_" + "0" if hchaindb.get_transaction(tx_fragment_id) != False: return True # verify that the incoming transaction is valid if len(transaction["vin"]) > 0: zero_inputs = False else: zero_inputs = True if tx.validate_transaction(transaction, zero_inputs) == False: raise (ValueError("invalid transaction received")) # add the transaction to the mempool mempool.append(transaction) # place the transaction on the P2P network for further # propagation propagate_transaction(transaction) except Exception as err: logging.debug('receive_transaction: exception: ' + str(err)) return False return True
def test_type_transaction(): """ test transaction type """ assert tx.validate_transaction([]) == False