区块链结构定义,它定义了一个类型,我使用类型
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,
}
此代码正在检查利害关系是否有效。该代码用于挖掘块,错误由is_staking_valid函数限制。我不知道它要求的是什么类型,因为我已经指定了一个。
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
}
}
}
请在
下面找到编译错误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`.
最小化示例:
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();
}
}
游乐场
这个错误的原因是Blockchain::<T1>::is_staking_valid
和Blockchain::<T2>::is_staking_valid
,以及编译器是两个独立的,完全不相关的函数。是的,它们有相同的代码,是的,它们将被优化器重复数据删除,但这并不一定是这种情况-例如,如果这个函数使用了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();
}
游乐场
由于可能存在歧义,编译器拒绝自己选择,并强制您显式地进行选择。
所以,你有几种可能的方法:
- 使
is_staking_valid
为自由函数,而不是Blockchain
的关联函数。在这种情况下,它不能依赖于Blockchain
的类型参数,因此调用将是明确的。 - 呼叫
Self::is_staking_valid
代替Blockchain::is_staking_valid
。在这种情况下,Self
将被Blockchain::<T>
取代,T
将从当前执行的方法中获取;这将再次解决歧义。 - 使
is_staking_valid
成为Blockchain
上的一个方法,即使其接收&self
,并通过self.is_staking_valid()
调用它。 - 不推荐,但仍然可能,-使
is_staking_valid
在Blockchain<T>
上为一些特定的T
关联函数,例如:
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();
}
}