Crates.io | pallas-miniprotocols |
lib.rs | pallas-miniprotocols |
version | 0.18.3 |
source | src |
created_at | 2022-02-12 23:01:24.053117 |
updated_at | 2024-10-23 20:19:53.560571 |
description | Implementation of the Ouroboros network mini-protocols state-machines |
homepage | https://github.com/txpipe/pallas |
repository | https://github.com/txpipe/pallas |
max_upload_size | |
id | 531542 |
size | 104,223 |
This crate provides an implementation of the different Ouroboros mini-protocols as defined in the The Shelley Networking Protocol specs.
The following architectural decisions were made for this particular Rust implementation:
mini-protocol | initiator | responder |
---|---|---|
block-fetch | done | planned |
chain-sync | done | planned |
handshake | done | planned |
local-state | done | planned |
tx-submission | planned | minimal |
local tx monitor | done | planned |
local-tx-submission | ongoing | planned |
An Ouroboros mini-protocol is defined as a state-machine. This library provides the primitive artifacts to describe the different states and messages of each particular state-machine.
A local agent, either initiator or responder, interacts with a remote agent by exchanging messages and keeping its own version of the state.
By implementing the following trait, a struct can participate as an agent in an Ouroboros communication:
pub trait Agent: Sized {
type Message;
fn is_done(&self) -> bool;
fn has_agency(&self) -> bool;
fn send_next(self, tx: &impl MachineOutput) -> Transition<Self>;
fn receive_next(self, msg: Self::Message) -> Transition<Self>;
}
Message
is an enum with the particular variants of each particular miniprotocolhas_agency
function describes if the agent has agency for the current state.is_done
function describes if the agent considers that all tasks have been done.send_next
function instructs the agent to send the next message in the sequence (will be called only if it has agency).receive_next
function instructs the agent to process the following received message.The send_next
and the receive_next
methods will transition the state-machine from one state to the following. This transition happens without mutating any value, the idea is that each step in the process transition the agent struct into a new struct of the same type describing the new state. This approach allows us to implement the execution of the state machine as a pure function.
To tigger the execution of an agent, the library provides the following entry-point:
run_agent<T>(agent: T, channel: &mut Channel)
Where T
is the type of the concrete agent to execute and the Channel
is the Ouroboros multiplexer channel already connected to the remote party.
The following example shows how to execute a Handshake client against a remote relay node.
// setup a TCP bearer against a relay node
let bearer = TcpStream::connect("relays-new.cardano-mainnet.iohk.io:3001").unwrap();
bearer.set_nodelay(true).unwrap();
bearer.set_keepalive_ms(Some(30_000u32)).unwrap();
// create a new multiplexer, specifying which mini-protocol IDs we want to sue
let mut muxer = Multiplexer::setup(bearer, &[0]).unwrap();
// get a handle for the handhsake mini-protocol handle
let mut channel = muxer.use_channel(0);
// create a handshake client agent with an initial state
let agent = handshake::Client::initial(VersionTable::v4_and_above(MAINNET_MAGIC));
// run the agent, which internally executes all the transitions
// until it is done.
let agent = run_agent(agent, &mut channel).unwrap();
// print the final state of the agent
println!("{agent:?}");