-1

Description: I am running this code but I keep getting the following error.

error[E0502]: cannot borrow `*graph` as mutable because it is also borrowed as immutable
   --> chain/chain.rs:111:12
    |
103 |         for tx in graph.iter() {
    |                   ------------ immutable borrow occurs here
...
111 |         if is_valid_transaction(graph, selected[i].1) == true {
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------^^^^^^
    |            |                           |
    |            |                           immutable borrow later used here
    |            mutable borrow occurs here

error[E0507]: cannot move out of index of `Vec<&(&str, Transaction)>`
   --> chain/chain.rs:111:40
    |
111 |         if is_valid_transaction(graph, selected[i].1) == true {
    |                                        ^^^^^^^^^^^^^ move occurs because value has type `Transaction`, which does not implement the `Copy` trait

What makes this unique (I hope) and not a duplicate is when I change graph.iter to graph.iter_mut() I get this error.

 error[E0499]: cannot borrow `*graph` as mutable more than once at a time
   --> chain/chain.rs:103:19
    |
103 |         for tx in graph.iter_mut() {
    |                   ^^^^^^^^^^^^^^^^ `*graph` was mutably borrowed here in the previous iteration of the loop

error[E0499]: cannot borrow `*graph` as mutable more than once at a time
   --> chain/chain.rs:111:33
    |
103 |         for tx in graph.iter_mut() {
    |                   ---------------- first mutable borrow occurs here
...
111 |         if is_valid_transaction(graph, selected[i].1) == true {
    |                                 ^^^^^  -------- first borrow later used here
    |                                 |
    |                                 second mutable borrow occurs here

Also, it seems like I need lifetime parameters, or else I will get more errors in my code.

Code (import the rand crate here: https://crates.io/crates/rand):

pub struct Transaction {
    pub sender_address: &'static str,
    pub receiver_address: &'static str,
    pub amount: f64,
    pub timestamp: String,
    pub signature: &'static str,
    pub weight: u128,
    pub edges: Vec<Transaction>, // I have no clue the true type
    pub index: usize,
}


fn is_valid_transaction (graph: &mut Vec<(&'static str, Transaction)> , transaction: Transaction) -> bool {
    if transaction.amount == 0.0 {
        println!("You can't send 0");
        return false;}
        

    if transaction.amount < 0.0 {
        println!("You can't send negative quantities");
        return false;}

    if transaction.sender_address == transaction.receiver_address {
        println!("You can't send to yourself");
        return false;}

    if transaction.signature.len() != 64 {
        println!("Invalid signature");
        return false;}

    else {return true;}
}

fn generate_random_indexes (graph: &mut Vec<(&'static str, Transaction)>) -> (usize, usize) {
    let mut rng = rand::thread_rng();
    let index_one = rng.gen_range(0..5000);
    let mut index_two = rng.gen_range(0..5000);
    while index_one == index_two {
        index_two = rng.gen_range(0..5000);
    }
    return (index_one, index_two);
}

// (&'a mut (&'static str, Transaction), &'a mut (&'static str, Transaction), u128)

fn select_edges_and_confirm_transactions <'a> (graph: &'a mut Vec<(&'static str, Transaction)>)
    -> ((&'a str, Transaction), (&'a str, Transaction), u128) {
    let (index_one, index_two) = generate_random_indexes(graph);
    let mut selected: Vec<(&(&'static str, Transaction))> = Vec::new();
    for i in 0..2 {
        for tx in graph.iter() {
            if tx.1.index == index_one || tx.1.index == index_two {
                selected.push(tx);
            }
        }
    }

    for i in 0..2 {
        if is_valid_transaction(graph, selected[i].1) == true {
            continue;
        } else {
            panic!("Found an invalid transaction!");
        }
    }

    let tx_one = selected[0].clone();
    let tx_two = selected[1].clone();
    let cumulative = &selected[0].1.weight + &selected[1].1.weight;

    return (tx_one, tx_two, cumulative);
}
  • 2
    You're not showing the `is_valid_transaction` function, but I suspect from the error message that it takes a `&mut Vec<…>` as its first parameter. Does it really need a mutable borrow of the graph? – Jmb Jul 05 '22 at 06:21
  • It is used in a function that needs it to be mutable, hence that is why it is mutable. –  Jul 05 '22 at 13:18
  • Would you like to see the whole file? –  Jul 05 '22 at 13:19
  • We need at least the prototype for `is_valid_transaction` (the one you've added is obviously wrong since it doesn't take any parameters) and ideally a [mre] (best would be if you can reproduce the issue on the [playground](https://play.rust-lang.org/)). – Jmb Jul 05 '22 at 14:37

1 Answers1

0

The variable graph is not used in fn is_valid_transation(...). Get rid of it.

If you don't want to because you'll add it later you can clone the tx and change the selected vector to not contain references to tuples but tuples directly. To do that you need to derive the Clone trait on the struct Transaction. By pushing tx (which is of type &(&str, Transaction)) to a vector you're merely pushing a reference to an item already present in your graph vector, which compiler complains about because you're also borrowing the vector mutably in the function call. This function call could change graph, changing the item you withdraw from selected. It's better to clone the data than try to borrow it mutably and immutably at the same time, or borrow it mutably twice.

Also change the is_valid_transaction signature to take a &Transaction instead of Transaction, and pass selected[i].1 as a reference. You probably can do that with the rest of the functions in your code in general. Here's a link to the playground with all that done