Peer state with tokio

Hello, I’m learning rust and cryptocurrency (by trying to replicate some of bitcoin on rust) with a colleague, and we came across tokio and some other macro crates, and after studying some of it, we are finding it very useful when thinking about the system.

We can treat a peer as an instance of a state machine, and this is supposed to be run async.
(I apologize for the boilerplate on the image and code.)

state flow image

The Idea here is that every time a peer connects (telnet localhost 8080), it starts in the “welcome” state, then immediately transitions to the “standby”. If the peer sends “PING?”, it goes to the “waiting” state; then it may send “BYE” and have its connection closed, or say “A” and go into another state, called “ComposedState”, which is another machine state itself.

why an inner machine

When wondering how we would wire up the future’s notification flow, we concluded we couldn’t try using async::await!(), since it will create sub-states in it’s own way and probably will have to move the state’s internal information ownership into each inner-state, as it passes thru them.

We intend to use only a (protocol)message (decoded from socket) or an admin command (such as “kill all peers”) future that could wake up an outer state to get transitioned–by using futures::select. Therefore, since a peer state may need some “execution” that can be run async, this can’t happen inside a state transition logic, only on state borderlines (before starting a transition-- so the next state can poll-depend on the future started on the previous state).

Without await!() and not wanting to mix inner state logic with outer states, we tested and confirmed we can treat a machine future as a state (by the crates we are using).

So after the peer said “A”, it moved into the sub-machine, which starts at “innerA” state. Then if the peer says “B”, it moves into the “InnerB” state, otherwise it will go to the “InnerEnd” state (so the outer machine will actually evaluate this). From the “InnerB” state, whatever the player says will move him to the “InnerEnd” state, and whatever he said will be evaluated by the outer machine. This outer state will evaluate the said message: if it’s “PING”, it will reply PONG and move the peer back to “standby”, otherwise it will be moved back into “waiting” state.

Given this test prototype, we believe it’s possible to have such arrangement:

peer control image

So the peer could have it’s own place in the network proto state machine; could get admin interferance thru channels; could queue messages from others as well (the admin could push standard transaction messages to be transmitted into the channel, and the peer could add in some internal vector; and then finally read and react to some when in standby); and the peer could ask some “executor helper” for something to get executed, then use inner state machines to progress. The “executer helper” could shot back (futures::OneShot) the result, waking the innerstate up and stuff would move on, all async…

This is the main.rs. We used tokio (tokio.rs/docs/getting-started/chat/) and also future_state_machine (github .com/fitzgen/state_machine_future).

[I removed some links because I can’t post more than 2]
[I divided the post in 2 so that the image could be seen (I can only post 1 per post)]

Just an update, the node managed to connect and handshake with a couple of peers, and the behavior is quite visible according to state transitions.

for example, this code https://github.com/swfsql/rustbtc/blob/master/src/actor/peer/machina/handshake.rs#L36 (an inner behaviour-state-machine) has a visual representation:

informal state transitions picture

handshake(1)

But I suppose we will learn and think more about the architecture before refactoring/continuing!