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 make_miner_keys(): """ makes a public-private key pair that the miner will use to receive the mining reward and the transaction fee for each transaction. This function writes the keys to a file and returns hash: RIPEMD160(SHA256(public key)) """ try: keys = rcrypt.make_ecc_keys() privkey = keys[0] pubkey = keys[1] pkhash = rcrypt.make_SHA256_hash(pubkey) mdhash = rcrypt.make_RIPEMD160_hash(pkhash) # write the keys to file with the private key as a hexadecimal string f = open('coinbase_keys.txt', 'a') f.write(privkey) f.write('\n') # newline f.write(pubkey) f.write('\n') f.close() except Exception as err: logging.debug('make_miner_keys: exception: ' + str(err)) return mdhash
def make_keys(): """ makes a private-public key pair for the synthetic previous transaction """ prev_tx_keys.clear() key_pair = rcrypt.make_ecc_keys() prev_tx_keys.append([key_pair[0],key_pair[1]]) return
def test_scriptsig_length_error(): """ test if the ScriptSig list has invalid length """ txn = make_synthetic_transaction(2) indices = randomize_list(txn['vin']) keys = rcrypt.make_ecc_keys() for ctr in list(range(len(indices))): txn["vin"][indices[ctr]]['ScriptSig'].append(keys[1]) assert tx.validate_vin(txn['vin'][indices[ctr]]) == False
def test_sign_message(message, value): """ Digitally sign a message and then verify it """ ecc_tuple = rcrypt.make_ecc_keys() priv_key = ecc_tuple[0] pub_key = ecc_tuple[1] sig = rcrypt.sign_message(priv_key, message) ret = rcrypt.verify_signature(pub_key, message, sig) assert ret == value
def test_make_ecc_keys(): """ test ECC private-public key pair """ ecc_keys = rcrypt.make_ecc_keys() assert ecc_keys[0].find("BEGIN PRIVATE KEY") >= 0 assert ecc_keys[0].find("END PRIVATE KEY") >= 0 assert ecc_keys[0].find("END PRIVATE KEY") > ecc_keys[0].find( "BEGIN PRIVATE KEY") assert ecc_keys[1].find("BEGIN PUBLIC KEY") >= 0 assert ecc_keys[1].find("END PUBLIC KEY") >= 0 assert ecc_keys[1].find("END PUBLIC KEY") > ecc_keys[1].find( "BEGIN PUBLIC KEY")
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
def test_unlock_bad_signature(monkeypatch): """ test unlocking a transaction with a bad signature """ global prev_tx_keys prev_tx_keys.clear() txn1 = make_synthetic_previous_transaction(4) txn2 = make_synthetic_transaction(2) # make a transaction fragment where the first vin element # of txn2 consumes the value of the first vout element of txn1 # synthetic consuming vin element in tx2 vin = {} vin['txid'] = txn1["transactionid"] vin['vout_index'] = 0 vin['ScriptSig'] = {} # use wrong private key to sign key_pair = rcrypt.make_ecc_keys() signature = rcrypt.sign_message(key_pair[0], prev_tx_keys[1][1]) pubkey = prev_tx_keys[1][1] sig = [] sig.append(signature) sig.append(pubkey + "corrupted") vin['ScriptSig'] = sig # public key hash in txn2 ripemd_hash = rcrypt.make_RIPEMD160_hash(rcrypt.make_SHA256_hash(prev_tx_keys[1][1])) fragment = { "value": 210, "pkhash": ripemd_hash, "spent": False, "tx_chain": txn2["transactionid"] + "_" + "0", "checksum": rcrypt.make_SHA256_hash(txn1["transactionid"]) } assert tx.unlock_transaction_fragment(vin, fragment) == 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 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 create_keys(): key_pair = rcrypt.make_ecc_keys() wallet_state["keys"].append(key_pair)