master chief
master chief

Reputation: 35

How do i resolve type annotations needed cannot infer type for type parameter `T` ? What type annotation is needed to compile this code?

The blockchain struct definition, It defines a type and i use the type

pub struct Blockchain<T = SledDb> {
    pub storage: T,
    pub chain: Vec<Block>,
    pub tip: Arc<RwLock<String>>,
    pub height: AtomicUsize,
    pub mempool: Mempool,
    pub wallet: Wallet,
    pub accounts: Account,
    pub stakes: Stake,
    pub validators: Validator,
}

This code is checking if stake is valid.The code for mining a block, the error is immited by is_staking_valid function. I don't know what type its asking for since i already specified one.

impl<T: Storage> Blockchain<T> {
    pub fn is_staking_valid(
            balance: u64,
            difficulty: u32,
            timestamp: i64,
            prev_hash: &String,
            address: &String,
        ) -> bool {
            let base = BigUint::new(vec![2]);
            let balance_diff_mul = base.pow(256) * balance as u32;
            let balance_diff = balance_diff_mul / difficulty as u64;
    
            let data_str = format!("{}{}{}", prev_hash, address, timestamp.to_string());
            let sha256_hash = digest(data_str);
            let staking_hash = BigUint::parse_bytes(&sha256_hash.as_bytes(), 16).expect("msg");
    
            staking_hash <= balance_diff
        }
    pub fn mine_block(&mut self, data: &str) -> Option<Block> {

        if self.mempool.transactions.len() < 2 {
            info!("Skipping mining because no transaction in mempool");
            return None;
        }

        let balance = self
            .stakes
            .get_balance(&self.wallet.get_public_key())
            .clone();

        let difficulty = self.get_difficulty();
        info!("New block mining initialized with difficulty {}", difficulty);

        let timestamp = Utc::now().timestamp();
        let prev_hash = self.chain.last().unwrap().hash.clone();
        let address = self.wallet.get_public_key();


        if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){

        let block = self.create_block(&data, timestamp);
        self.storage.update_blocks(&prev_hash, &block, self.height.load(Ordering::Relaxed));
        Some(block)
        } else {
           None
        }
    }
}
 

Please find the compiler error below

error[E0282]: type annotations needed
   --> src/blocks/chain.rs:173:12
    |
173 |         if Blockchain::is_staking_valid(balance, difficulty, timestamp, &prev_hash, &address){
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T`

For more information about this error, try `rustc --explain E0282`.

Upvotes: 0

Views: 2796

Answers (1)

Cerberus
Cerberus

Reputation: 10218

Minimized example:

pub struct Blockchain<T> {
    pub storage: T,
}

impl<T> Blockchain<T> {
    pub fn is_staking_valid() {
        todo!()
    }
    pub fn mine_block(&mut self) {
        Blockchain::is_staking_valid();
    }
}

Playground

The reason for this error is that Blockchain::<T1>::is_staking_valid and Blockchain::<T2>::is_staking_valid are, as well as compiler is concerned, two separate, entirely unrelated functions. Yes, they have the same code, and yes, they will be deduplicated by the optimizer, but this doesn't have to be the case - e.g., if this function used some associated item available on T:

trait Stakable {
    const IS_VALID: bool;
}
impl Stakable for () {
    const IS_VALID: bool = false;
}
impl Stakable for i32 {
    const IS_VALID: bool = true;
}

struct Blockchain<T> {
    pub _storage: T,
}

impl<T: Stakable> Blockchain<T> {
    fn validate() {
        if !T::IS_VALID {
            panic!("Type is not valid");
        }
    }
}

fn main() {
    // This panics - we catch this panic and show that it has indeed happened
    std::panic::catch_unwind(|| Blockchain::<()>::validate()).unwrap_err();
    // This executes successfully
    Blockchain::<i32>::validate();
}

Playground

Because of the possible ambiguity, compiler refuses to choose by itself and forces you to make the selection explicitly.


So, you have several possible ways to go:

  • Make is_staking_valid a free function, instead of associated function of Blockchain. In this case, it won't be able to depend on Blockchain's type parameter, therefore the call will be unambiguous.
  • Call Self::is_staking_valid instead of Blockchain::is_staking_valid. In this case, Self will be replaced with Blockchain::<T>, with T taken from the currently executed method; this will, again, resolve ambiguity.
  • Make is_staking_valid a method on Blockchain, i.e. make it receive &self, and call it via self.is_staking_valid().
  • Not recommended, but still possible, - make is_staking_valid an associated function on Blockchain<T> for some specific T, e.g.:
pub struct Blockchain<T> {
    pub storage: T,
}

impl Blockchain<()> {
    // Note - no free type parameters here!
    pub fn is_staking_valid() {
        todo!()
    }
}

impl<T> Blockchain<T> {
    pub fn mine_block(&mut self) {
        // Here, `Blockchain` is `Blockchain::<()>` - the method is set
        Blockchain::is_staking_valid();
    }
}

Upvotes: 2

Related Questions