1

I'm a beginner at Rust and I've been following this tutorial on creating a simple blockchain using Rust.

chain.rs

use byteorder::{BigEndian, ReadBytesExt};
use chrono::offset::Utc;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::io::Cursor;

//  Represents the entire chain in the network
pub struct Chain {
    //  Actual chain
    pub blocks: Vec<Block>,
}

//  Represents a single block in the blockchain
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Block {
    pub id: u64,

    //  Hash representing block
    pub hash: String,

    //  Hash of the previous block
    pub previous_hash: String,

    //  Time of creation in UTC
    pub timestamp: i64,

    //  Data contained in the block
    pub data: String,

    //  Value for hashing the block(PoW)
    pub nonce: u64,
}

p2p.rs

use std::collections::HashSet;

use super::chain::{Block, Chain};
use libp2p::{
    floodsub::{Floodsub, FloodsubEvent, Topic},
    identity::Keypair,
    mdns::{Mdns, MdnsEvent},
    swarm::{NetworkBehaviourEventProcess, Swarm},
    NetworkBehaviour, PeerId,
};
use log::{error, info};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use serde_json;
use tokio::sync::mpsc;

//  Topics for pub/sub protocol
//  Impairements: Broadcasts on each request thus extremely inefficient
pub static BLOCK_TOPIC: Lazy<Topic> = Lazy::new(|| Topic::new("blocks"));
pub static CHAIN_TOPIC: Lazy<Topic> = Lazy::new(|| Topic::new("chains"));

//  Key Pair for peer identification on network
pub static KEYS: Lazy<Keypair> = Lazy::new(Keypair::generate_ed25519);

//  Peer id for peer identification on network
pub static PEER_ID: Lazy<PeerId> = Lazy::new(|| PeerId::from(KEYS.public()));

 ...
//  Defines overall NetworkBehaviour for the chain
#[derive(NetworkBehaviour)]
pub struct ChainBehaviour {
    //  Chain
    #[behaviour(ignore)]
    pub chain: Chain,

    //  Handles FloodSub protocol
    pub floodsub: Floodsub,

    //  Sends response to the UnboundedReceiver
    #[behaviour(ignore)]
    pub init_sender: mpsc::UnboundedSender<bool>,

    //  Handles automatic discovery of peers on the local network
    //  and adds them to the topology
    pub mdns: Mdns,

    //  Sends response to the UnboundedReceiver
    #[behaviour(ignore)]
    pub response_sender: mpsc::UnboundedSender<ChainResponse>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ChainResponse {
    pub blocks: Vec<Block>,
    pub receiver: String,
}

//  Triggers chain communication for requested ID
#[derive(Debug, Deserialize, Serialize)]
pub struct LocalChainRequest {
    pub from_peer_id: String,
}

//  Keep states for handling incoming messages, lazy init
//  and keyboard input by the client's user
pub enum EventType {
    LocalChainRequest(ChainResponse),
    Input(String),
    Init,
}

//  Implemnt FloodsubEvent for ChainBehaviour
impl NetworkBehaviourEventProcess<FloodsubEvent> for ChainBehaviour {
    fn inject_event(&mut self, event: FloodsubEvent) {
        if let FloodsubEvent::Message(msg) = event {
            //  If message is of type ChainResponse and that the message is ours,
            //  we execute our consensus.
            if let Ok(response) = serde_json::from_slice::<ChainResponse>(&msg.data) {
                if response.receiver == PEER_ID.to_string() {
                    info!("Response from {}:", msg.source);
                    response.blocks.iter().for_each(|r| info!("{:?}", r));

                    self.chain.blocks = self
                        .chain
                        .choose(self.chain.blocks.clone(), response.blocks);
                }
            } else if let Ok(response) = serde_json::from_slice::<LocalChainRequest>(&msg.data) {
                //  If of type LocalChainRequest, we send ChainResponse to
                //  initiator
                info!("sending local chain to {}", msg.source.to_string());
                let peer_id = response.from_peer_id;

                if PEER_ID.to_string() == peer_id {
                    if let Err(e) = self.response_sender.send(ChainResponse {
                        blocks: self.chain.blocks.clone(),
                        receiver: msg.source.to_string(),
                    }) {
                        error!("error sending response via channel, {}", e);
                    };
                }
            } else if let Ok(block) = serde_json::from_slice::<Block>(&msg.data) {
                //  If of type Block, we try adding the block if valid
                info!("received new block from {}", msg.source.to_string());
                self.chain.try_add_block(block);
            }
        }
    }
}

//  Implement MdnsEvents for ChainBehaviour
impl NetworkBehaviourEventProcess<MdnsEvent> for ChainBehaviour {
    fn inject_event(&mut self, event: MdnsEvent) {
        match event {
            //  Add node to list of nodes when discovered
            MdnsEvent::Discovered(nodes) => {
                for (peer, _) in nodes {
                    self.floodsub.add_node_to_partial_view(peer)
                }
            }
            //  Remove node from list of nodes when TTL expires and
            //  address hasn't been refreshed
            MdnsEvent::Expired(nodes) => {
                for (peer, _) in nodes {
                    if !self.mdns.has_node(&peer) {
                        self.floodsub.remove_node_from_partial_view(&peer);
                    }
                }
            }
        }
    }
}

Here's my cargo.toml:

byteorder = "1"
chrono = "0.4.19"
getrandom = "0.2.3"
hex = "0.4.3"
libp2p = {version = "0.41.0", features = ['tcp-tokio', "mdns"]}
log = "0.4.14"
once_cell = "1.9.0"
oorandom = "11.1.3"
pretty_env_logger = "0.4.0"
serde = {version = "1.0.133", features = ["derive"]}
serde_json = "1.0.74"
sha2 = "0.10.0"
tokio = { version = "1.15.0", features = ["io-util", "io-std", "macros", "rt", "rt-multi-thread", "sync", "time"] }

I keep getting the following error on this struct:

error[E0277]: the trait bound `(): From<MdnsEvent>` is not satisfied
  --> src/p2p.rs:30:10
   |
30 | #[derive(NetworkBehaviour)]
   |          ^^^^^^^^^^^^^^^^ the trait `From<MdnsEvent>` is not implemented for `()`
   |
   = help: see issue #48214
   = note: this error originates in the derive macro `NetworkBehaviour` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `(): From<FloodsubEvent>` is not satisfied
  --> src/p2p.rs:30:10
   |
30 | #[derive(NetworkBehaviour)]
   |          ^^^^^^^^^^^^^^^^ the trait `From<FloodsubEvent>` is not implemented for `()`
   |
   = help: see issue #48214
   = note: this error originates in the derive macro `NetworkBehaviour` (in Nightly builds, run with -Z macro-backtrace for more info)

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

I tried following the suggestions from this forum and got the following error:

error[E0599]: no method named `into_inner` found for struct `OneShotHandler` in the current scope
  --> src/p2p.rs:30:10
   |
30 | #[derive(NetworkBehaviour)]
   |          ^^^^^^^^^^^^^^^^ method not found in `OneShotHandler<FloodsubProtocol, FloodsubRpc, floodsub::layer::InnerMessage>`
   |
   = note: this error originates in the derive macro `NetworkBehaviour` (in Nightly builds, run with -Z macro-backtrace for more info)

I also keep getting an add reference here error on #[derive(NetworkBehaviour)]. What could be causing the error and how can I fix it? I'm using rust-analyzer.

Link to the tutorial's github repo.

Link to my github repo. The entire code is rather large but should only the afforementioned errors.

Zeddling
  • 13
  • 4
  • Please post the full error messages, including line numbers, code extracts and compiler suggestions. – Jmb Jan 07 '22 at 11:11
  • I hope that's okay? – Zeddling Jan 07 '22 at 11:31
  • The tutorial did not include the `use` statements, but you should include them here, as well as the library crate versions used. – E_net4 Jan 07 '22 at 12:33
  • @E_net4thecurator I've added a link to the tutorial's github repo. It was at the end of the article. – Zeddling Jan 07 '22 at 18:24
  • A link to a repository does not constitute a minimal reproducible example on this platform. Questions need to be self sufficient. – E_net4 Jan 07 '22 at 19:33
  • @E_net4thecurator I've added my dependencies and additional code from another file – Zeddling Jan 08 '22 at 03:01
  • @E_net4thecurator I've made more updates to the post and also added a link to my git repository. It should show the same errors(12) and other errors related to the ones I've mentioned. – Zeddling Jan 08 '22 at 03:07

1 Answers1

0

This question is nearly a year old, but maybe will run into this again in the future.

I stumbled over the same issue, funnily enough while working through the same tutorial. It seems that newer versions of libp2p require you to do two things that the version used for the tutorial did not seem to require:

  1. Specify #[behaviour(out_event="Event")] For the AppBehaviour struct
    • This is mentioned to be optional in the docs, but if you don't specify this then the macro will use StructName<Event>.
  2. Implement the trait From<> for the enum Event for all events emitted by struct members of AppBehaviour, as the events emitted by the struct members are wrapped in the event enum.

I've added two new enum values for this as shown in the libp2p docs:

use crate::net::{ChainResponse};

use libp2p::{floodsub::FloodsubEvent, mdns::MdnsEvent};

pub enum Event {
    ChainResponse(ChainResponse),
    Floodsub(FloodsubEvent),
    Mdns(MdnsEvent),
    Input(String),
    Init,
}

impl From<FloodsubEvent> for Event {
    fn from(event: FloodsubEvent) -> Self {
        Self::Floodsub(event)
    }
}

impl From<MdnsEvent> for Event {
    fn from(event: MdnsEvent) -> Self {
        Self::Mdns(event)
    }
}
David Wright
  • 464
  • 6
  • 18