Reputation: 35
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
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();
}
}
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();
}
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:
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.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.is_staking_valid
a method on Blockchain
, i.e. make it receive &self
, and call it via self.is_staking_valid()
.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