Vec type does not implement the `Copy` trait

#1

I’m trying to understand blockchain through coding, the first step is each block to have a hash based on its content, that is used to connect it to the next block, and so on.
So, the Block::new is building the block with no hash, then make special hash baed on the content, then the Block.hash is updated based on the generated hash code.

I’ve the below definition.rs:

use serde_derive::*;

pub type BlockHash = Vec<u8>;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Transaction {
    pub id: String,
    pub timestamp: u64,
    pub payload: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Block {
    pub index: u32,
    pub timestamp: u128,
    pub hash: BlockHash,
    pub prev_block_hash: BlockHash,
    pub nonce: u64,
    pub payload: Vec<Transaction>,
}

And the below block_new.rs file:

use crate::definition::{Block,Transaction};

impl Block {
    pub fn new (previous_block: &Block, timestamp: u128,
            nonce: u64, payload: Vec<Transaction>) -> Block {
        let block: Block = Block {
            index: &previous_block.index + 1,
            timestamp,
            hash: vec![],
            prev_block_hash: previous_block.hash.to_vec(), 
            nonce,   // proof: 0,
            payload,
        };

        Block {
            index: previous_block.index + 1,
            timestamp,
            hash: block.hash256(),
            prev_block_hash: previous_block.hash.to_vec(),
            nonce,   // proof: 0,
            payload,
        }
    }
}

impl Block {
    fn hash256 (&self) -> Vec<u8> {
        crypto_hash::digest(
            crypto_hash::Algorithm::SHA256,
            &self.bytes(),
        )
    }
}

But looks i’ve some issue with borrowing, I tried to manage it, but stuck with the below error:

error[E0382]: use of moved value: `payload`
  --> src/block_new.rs:23:13
   |
7  |             nonce: u64, payload: Vec<Transaction>) -> Block {
   |                         ------- move occurs because `payload` has type `std::vec::Vec<definition::Transaction>`, which does not implement the `Copy` trait
...
14 |             payload,
   |             ------- value moved here
...
23 |             payload,
   |             ^^^^^^^ value used here after move

error: aborting due to previous error

When I changed the derived of the struct to be:

#[derive(Serialize, Deserialize, Debug, Copy)]
pub struct Transaction {
    pub id: String,
    pub timestamp: u64,
    pub payload: String,
}

I got the below error:

error[E0204]: the trait `Copy` may not be implemented for this type
 --> src/definition.rs:5:41
  |
5 | #[derive(Serialize, Deserialize, Debug, Copy)]
  |                                         ^^^^
6 | pub struct Transaction {
7 |     pub id: String,
  |     -------------- this field does not implement `Copy`
8 |     pub timestamp: u64,
9 |     pub payload: String,
  |     ------------------- this field does not implement `Copy`

error: aborting due to previous error
0 Likes

#2

Only types that live fully on the stack can implement Copy. Implementing Copy basically means that a value of that type can be cloned by doing a bitwise copy of its stack representation, which in turn means that moving a value of a Copy type does not invalidate the previous owner but creates a clone instead. String stores its contents on the heap and so it’s not Copy. Through transitivity Transaction can also not be Copy. That’s why adding the Copy type to the derive macro didn’t work. Vec is also not Copy since it stores its contents on the heap, so a Vec<Transaction> is definitely not Copy.

The compiler tells you that on line 14 you move payload. Since it is not a Copy type you don’t have ownership of it anymore. Thus when you try to move it again on line 23 the compiler complains about a “use of moved value”.

You could fix the issue by explicitly cloning the payload on line 14: payload.clone(). But I believe that’s not actually what you want to do. The new method should probably only create one Block so I don’t know why you create two. Did you intend something like this?:

pub fn new (previous_block: &Block, timestamp: u128, nonce: u64, payload: Vec<Transaction>) -> Block {
    let block: Block = Block {
        Index: &previous_block.index + 1,
        ...
    };
    block
}

Basically replacing the last eight lines of your original new function (which create a second Block for no apparent reason) by block.

0 Likes