def make_synthetic_vin(transaction, vin_index): """ make a vin object """ vin = {} # get a transaction fragment to consume from HeliumDB # get some random block earlier then our consuming block # select a random vout element # check Heliumb to see if output spent # if not add it # get a transaction fragment to consume for ctr in range(10): if wfragment["spent"] == False: break if ctr == 10: return False # could not get any inputs vin['txid'] = wfragment["transactionid"] vin['vout_index'] = wfragment["vout_index"] keys = tx_keys[wfragment["transactionid"]] vin['ScriptSig'] = [] vin["ScriptSig"].append(rcrypt.sign_message(keys[0], keys[1])) vin["ScriptSig"].append(keys[1]) return vin
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 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_synthetic_vin(prev_txid, prev_tx_vout_index): """ make a vin object, receives a previous transaction id and a index into the vout list returns the vin elemment """ vin = {} vin['txid'] = prev_txid vin['vout_index'] = prev_tx_vout_index vin['ScriptSig'] = [] vin['ScriptSig'].append(rcrypt.sign_message(prev_tx_keys[0][0], prev_tx_keys[0][1])) vin['ScriptSig'].append(prev_tx_keys[0][1]) return vin
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_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