def make_synthetic_transaction(): """ 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 vin list vin = {} vin["txid"] = rcrypt.make_uuid() vin["vout_index"] = 0 vin["ScriptSig"] = [] vin["ScriptSig"].append(rcrypt.make_uuid()) vin["ScriptSig"].append(rcrypt.make_uuid()) transaction['vin'].append(vin) # make vout list vout = {} vout["value"] = secrets.randbelow(10000000) +1000 vin["ScripPubKey"] = [] transaction['vout'].append(vout) return transaction
def make_random_transaction(block_height): tx = {} tx["version"] = "1" tx["transactionid"] = rcrypt.make_uuid() tx["locktime"] = secrets.randbelow(hconfig.conf["MAX_LOCKTIME"]) # public-private key pair for previous transaction prev_keys = rcrypt.make_ecc_keys() # public-private key pair for this transaction keys = rcrypt.make_ecc_keys() # Build vin tx["vin"] = [] if block_height > 0: ctr = secrets.randbelow(hconfig.conf["MAX_INPUTS"]) + 1 ind = 0 while ind < ctr: signed = rcrypt.sign_message(prev_keys[0], prev_keys[1]) ScriptSig = [] ScriptSig.append(signed[0]) ScriptSig.append(prev_keys[1]) tx["vin"].append({ "txid": rcrypt.make_uuid(), "vout_index": ctr, "ScriptSig": ScriptSig }) ind += 1 # Build Vout tx["vout"] = [] ctr = secrets.randbelow(hconfig.conf["MAX_OUTPUTS"]) + 1 ind = 0 while ind < ctr: ScriptPubKey = [] ScriptPubKey.append("DUP") ScriptPubKey.append("HASH-160") ScriptPubKey.append(keys[1]) ScriptPubKey.append("EQ_VERIFY") ScriptPubKey.append("CHECK-SIG") tx["vout"] = { "value": secrets.randbelow(10000000) + 1000000, # helium cents "ScriptPubKey": ScriptPubKey } ind += 1 return tx
def test_get_existing_tx(): """ test getting a block for an existing transaction """ txid = rcrypt.make_uuid() blkindex.put_index(txid, 555) assert blkindex.get_blockno(txid) == 555
def make_synthetic_transaction(prev_tx: "dictionary"): """ makes a synthetic transaction with randomized values and that draws inputs from the previous transaction """ transaction = {} transaction['version'] = 1 transaction['transactionid'] = rcrypt.make_uuid() transaction['locktime'] = 0 transaction['vin'] = [] transaction['vout'] = [] num_outputs = max(1, secrets.randbelow(9)) ctr = 0 while ctr < num_outputs: vout = make_synthetic_vout() transaction['vout'].append(vout) ctr += 1 # randomize how many of the previous transaction outputs # are consumed and the order in which they are consumed num_inputs = max(secrets.randbelow(len(prev_tx["vout"])), 1) indices = list(range(num_inputs)) random.shuffle(indices) for ctr in indices: vin = make_synthetic_vin(prev_tx["transactionid"], ctr) transaction['vin'].append(vin) ctr += 1 return transaction
def make_synthetic_blocks(num_blocks): """ make synthetic blocks for unit testing add the blocks to the blockchain """ for ctr in range(num_blocks): block = {} block["transactionid"] = rcrypt.make_uuid() block["version"] = hconfig.conf["VERSION_NO"] block["difficulty_bits"] = hconfig.conf["DIFFICULTY_BITS"] block["nonce"] = hconfig.conf["NONCE"] block["height"] = ctr block["timestamp"] = int(time.time()) block["tx"] = [] # add transactions to the block num_tx = secrets.randbelow(5) + 1 for __ctr in range(num_tx): trx = make_synthetic_transaction(block) block["tx"].append(trx) block["merkle_root"] = hblockchain.merkle_root(block["tx"], True) if ctr == 0: block["prevblockhash"] = "" else: block["prevblockhash"] = hblockchain.blockheader_hash( hblockchain.blockchain[ctr - 1]) # append block to blockchain hblockchain.blockchain.append(block) return
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 test_genesis_block_prev_hash(monkeypatch): """ test that the previous block hash for the genesis block is empty """ hblockchain.blockchain.clear() monkeypatch.setattr(hblockchain, "merkle_root", lambda x, y: rcrypt.make_SHA256_hash('msg0')) monkeypatch.setitem(block_0, "height", 0) monkeypatch.setitem(block_0, "prevblockhash", rcrypt.make_uuid()) assert len(hblockchain.blockchain) == 0 assert hblockchain.add_block(block_0) == False
def make_synthetic_block(): """ make synthetic block for unit testing """ block = {} block["transactionid"] = rcrypt.make_uuid() block["version"] = hconfig.conf["VERSION_NO"] block["difficulty_bits"] = hconfig.conf["DIFFICULTY_BITS"] block["nonce"] = hconfig.conf["NONCE"] block["height"] = 1024 block["timestamp"] = int(time.time()) block["tx"] = [] # add transactions to the block num_tx = secrets.randbelow(6) + 2 for __ctr in range(num_tx): trx = make_synthetic_transaction() block["tx"].append(trx) block["merkle_root"] = hblockchain.merkle_root(block["tx"], True) block["prevblockhash"] =rcrypt.make_uuid() return block
def make_coinbase_transaction(block_height: "integer", pubkey: "string") -> 'dict': """ makes a coinbase transaction, this is the miner's reward for mining a block. Receives a public key to denote ownership of the reward. Since this is a fresh issuance of heliums there are no vin elements. locks the transaction for hconfig["COINBASE_INTERVAL"] blocks. Returns the coinbase transaction. """ try: # calculate the mining reward reward = mining_reward(block_height) # create a coinbase transaction trx = {} trx['transactionid'] = rcrypt.make_uuid() trx['version'] = hconfig.conf["VERSION_NO"] # the mining reward cannot be claimed until approximately 100 blocks are mined # convert into a time interval trx['locktime'] = hconfig.conf["COINBASE_INTERVAL"] * 600 trx['vin'] = [] trx['vout'] = [] ScriptPubKey = [] ScriptPubKey.append('SIG') ScriptPubKey.append( rcrypt.make_RIPEMD160_hash(rcrypt.make_SHA256_hash(pubkey))) ScriptPubKey.append('<DUP>') ScriptPubKey.append('<HASH_160>') ScriptPubKey.append('HASH-160') ScriptPubKey.append('<EQ-VERIFY>') ScriptPubKey.append('<CHECK_SIG>') # create the vout element with the reward trx['vout'].append({'value': reward, 'ScriptPubKey': ScriptPubKey}) except Exception as err: logging.debug('make_coinbase_transaction: exception: ' + str(err)) return trx
def make_synthetic_previous_transaction(num_outputs): """ makes synthetic previous transaction with randomized values we abstract away the inputs to the previous transaction. """ transaction = {} transaction['version'] = 1 transaction['transactionid'] = rcrypt.make_uuid() transaction['locktime'] = 0 transaction['vin'] = [] transaction['vout'] = [] def make_synthetic_vout(): """ make a synthetic vout object. returns a vout dictionary item """ key_pair = rcrypt.make_ecc_keys() global prev_tx_keys prev_tx_keys.append([key_pair[0],key_pair[1]]) vout = {} vout['value'] = secrets.randbelow(1000000) + 1000 # helium cents tmp = [] tmp.append('<DUP>') tmp.append('<HASH-160>') tmp.append(key_pair[1]) tmp.append('<EQ-VERIFY>') tmp.append('<CHECK-SIG>') vout['ScriptPubKey'] = tmp return vout ctr = 0 while ctr < num_outputs: ret = make_synthetic_vout() transaction['vout'].append(ret) ctr += 1 return transaction
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 make_random_transaction(blockno, is_coinbase): txn = {} txn["version"] = "1" txn["transactionid"] = rcrypt.make_uuid() if is_coinbase == True: txn["locktime"] = hconfig.conf["COINBASE_LOCKTIME"] else: txn["locktime"] = 0 # the public-private key pair for this transaction transaction_keys = rcrypt.make_ecc_keys() # previous transaction fragments spent by this transaction total_spendable = 0 ####################### # Build the vin array ####################### txn["vin"] = [] # genesis block transactions have no prior inputs. # coinbase transactions do not have any inputs if (blockno > 0) and (is_coinbase != True): max_inputs = secrets.randbelow(hconfig.conf["MAX_INPUTS"]) if max_inputs == 0: max_inputs = hconfig.conf["MAX_INPUTS"] - 1 # get some random previous unspent transaction # fragments to spend ind = 0 ctr = 0 while ind < max_inputs: # get a random unspent fragment from a previous block index = secrets.randbelow(len(unspent_fragments)) frag_dict = unspent_fragments[index] key = [*frag_dict.keys()][0] val = [*frag_dict.values()][0] if val["blockno"] == blockno: ctr += 1 if ctr == 10000: print("failed to get random unspent fragment") return False continue unspent_fragments.pop(index) total_spendable += val["value"] tmp = hchaindb.get_transaction(key) if tmp == False: print("cannot get fragment from chainstate: " + key) assert tmp != False assert tmp["spent"] == False assert tmp["value"] > 0 # create a random vin element key_array = key.split("_") signed = rcrypt.sign_message(val["privkey"], val["pubkey"]) ScriptSig = [] ScriptSig.append(signed) ScriptSig.append(val["pubkey"]) txn["vin"].append({ "txid": key_array[0], "vout_index": int(key_array[1]), "ScriptSig": ScriptSig }) ctr = 0 ind += 1 ##################### # Build Vout list ##################### txn["vout"] = [] # genesis block if blockno == 0: total_spendable = secrets.randbelow(10_000_000) + 50_000 # we need at least one transaction output for non-coinbase # transactions if is_coinbase == True: max_outputs = hconfig.conf["MAX_OUTPUTS"] else: max_outputs = secrets.randbelow(hconfig.conf["MAX_OUTPUTS"]) if max_outputs <= 1: max_outputs = 2 ind = 0 while ind < max_outputs: tmp = rcrypt.make_SHA256_hash(transaction_keys[1]) tmp = rcrypt.make_RIPEMD160_hash(tmp) ScriptPubKey = [] ScriptPubKey.append("<DUP>") ScriptPubKey.append("<HASH-160>") ScriptPubKey.append(tmp) ScriptPubKey.append("<EQ-VERIFY>") ScriptPubKey.append("<CHECK-SIG>") if is_coinbase == True: value = hmining.mining_reward(blockno) else: amt = int(total_spendable / max_outputs) value = secrets.randbelow(amt) # helium cents if value == 0: value = int(amt / 10) total_spendable -= value assert value > 0 assert total_spendable >= 0 txn["vout"].append({"value": value, "ScriptPubKey": ScriptPubKey}) # save the transaction fragment fragid = txn["transactionid"] + "_" + str(ind) fragment = {} fragment[fragid] = { "value": value, "privkey": transaction_keys[0], "pubkey": transaction_keys[1], "blockno": blockno } unspent_fragments.append(fragment) #print("added to unspent fragments: " + fragid) if total_spendable <= 0: break ind += 1 return txn
def test_make_uuid(length, ret): """ test id generation """ id = rcrypt.make_uuid() assert (len(id) == length) == ret
def test_delete_tx(): txid = rcrypt.make_uuid() blkindex.put_index(txid, 555) assert blkindex.delete_index(txid) == True assert blkindex.get_blockno(txid) == False
def make_transactionid(): """ makes a random transaction id """ return rcrypt.make_uuid()
def setup_module(): assert bool(blkindex.open_blk_index("hblk_index")) == True if os.path.isfile("hblk_index"): os.remove("hblk_index") def teardown_module(): assert blkindex.close_blk_index() == True @pytest.mark.parametrize("txid, value, ret", [ ("", 9, False), ("abc", "", False), ('290cfd3f3e5027420ed483871309d2a0780b6c3092bef3f26347166b586ff89f', 10899, True), (rcrypt.make_uuid(), 9, True), (rcrypt.make_uuid(), -1, False), (rcrypt.make_uuid(), -56019, False), (rcrypt.make_uuid(), 90890231, True), ]) def test_put_index(txid, value, ret): """ tests putting valid and invalid transaction_index and blockno pairs into the blk_index store """ assert blkindex.put_index(txid, value) == ret def test_get_existing_tx(): """ test getting a block for an existing transaction
def make_pkhash(): """ creates a random pkhash value """ id = rcrypt.make_uuid() return rcrypt.make_RIPEMD160_hash(rcrypt.make_SHA256_hash(id))