def test_previous_tx_non_existent(): """ tests transaction update when a previous transaction does not exist """ # make a synthetic previous transaction num_prev_tx_outputs = secrets.randbelow(5) + 1 previous_tx = make_synthetic_previous_transaction(num_prev_tx_outputs) #reflect this previous transaction in HeliumDB ctr = 0 for vout in previous_tx["vout"]: #pdb.set_trace() fragment = {} fragment["pkhash"] = vout["ScriptPubKey"][2] fragment["spent"] = False fragment["value"] = max(secrets.randbelow(1000000), 10) fragment["tx_chain"] = "" txid = previous_tx["transactionid"] + "_" + str(ctr) chain.put_transaction( txid, fragment) ctr += 1 # make a transaction consuming some previous transaction outputs trx = make_synthetic_transaction(previous_tx) trx["vin"][0]["txid"] = "bad previous tx id" #update the Helium Chainstate assert chain.transaction_update(trx) == False
def make_synthetic_transaction(block): """ makes a synthetic transaction with randomized values """ transaction = {} transaction['version'] = hconfig.conf["VERSION_NO"] transaction['transactionid'] = rcrypt.make_uuid() transaction['locktime'] = 0 transaction['vin'] = [] transaction['vout'] = [] # make public-private key pair for the transaction pair = rcrypt.make_ecc_keys() tx_keys[transaction["transactionid"]] = pair # make vin list # genesis block does not have inputs if block["height"] > 0: num_inputs = secrets.randbelow(3) + 1 for ctr in range(num_inputs): trx = make_synthetic_vin(transaction, ctr) if trx == False: break transaction["vin"].append(trx) # make vout list num_outputs = secrets.randbelow(5) + 1 ctr = 0 for ctr in range(num_outputs): vout = make_synthetic_vout(block, transaction, ctr, pair[1]) if vout != False: transaction["vout"].append(vout) block["tx"].append(transaction) hchaindb.transaction_update(transaction) return transaction
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 build_chainstate(): ''' build the Chainstate database from the blockchain files ''' blockno = 0 tx_count = 0 try: while True: # test whether the block file exists block_file = "block" + "_" + str(blockno) + ".dat" if os.path.isfile(block_file) == False: break # load the block file into a dictionary object f = open(block_file, 'rb') block = pickle.load(f) # process the vout and vin arrays for each block transaction for trx in block["tx"]: ret = hchaindb.transaction_update(trx) tx_count += 1 if ret == False: raise ( ValueError("failed to rebuild chainstate. block no: " + str(blockno))) blockno += 1 except Exception as err: print(str(err)) return False print("transactions processed: " + str(tx_count)) print("blocks processed: " + str(blockno)) return True