massa
massa copied to clipboard
Encapsulate the bootstrap process in the type-system - server side
The bootstrap process on the server side can be broken down into the following steps:
- Accept a connection. This provides a TcpStream, and is functionally the same as
std::net::TcpListener::accept - Create a connection binding: This creates an object containing the stream, book-keeing data, and configugation variables
- Perform the handshake: This is done with a single stream read to obtain the first message-hash
- Confirm no-error: The server tries to get a message from client. If it takes too long, good: the client hasn't sent an error (Investigate not having to rely on a timeout)
- Send the client the servers time
- loop over messages received from client:
- timeout: break out of the bootstrap process with an
Ok(()) AskBootstrapPart=>stream_bootstrap_informaton(/* what the client currently has */)AskBootstrapMipStore=> send it to the clientBootstrapSuccess=> break out of the process with anOk(())BootstrapError=> break out of the process, returning the error
- timeout: break out of the bootstrap process with an
- Handle the result of said loop and end the session
stream_bootstrap_information
Is a loop that basically simplifies down to this:
loop {
/* checks what client currently has against what the client needs */
/* constructs a data packet to get client closer to what it needs */
if /* data-packet is empty */ {
return server.send_msg(BootstrapServerMessage::BootstrapFinished);
}
server.send_msg(/* data-packet */)?;
}
sending a message
Sending a message is not a simple tcp-stream write.
- Compute the message signature
- take the signature of the previous message (in byte-vec form) (handshake process creates first signature)
- append the bytes of the message to be sent
- use the servers keypair to sign these bytes
- send the message signature
- send the length of the message
- send the message itself
(could probably squash 2-4 into a single step)
possible states:
- expecting send
- send-in-progress(bytes sent/remaining)
- send-complete
- send-failed(bytes sent/remaining)
reading a message
- Reads 32 bytes from the client (in order to verify a signature)
- reads the bytes needed to decode the length of the message from the client (and decodes it)
- reads the number of bytes that was encoded in the previous read
- checks that the bytes received in step 1 matches the most recently sent message signature
- concatenates the bytes received in step 1 and 3
- computes the hash of this concatenation
- updates the servers most recent message-hash with this new hash
possible states:
- expecting read
- reading signature and message length (bytes remaining)
- reading message (bytes remaining)
- failed read: message sequencing broken because received signature doesn't match previously sent signature
- failed read: bad message deserialisation
- good read (with resulting mesage)
state-spike can be found on the bootstrap/state-spike branch. It attempts to change the pattern from fn some_func(&mut self, ...) -> ...; to fn some_funct(mut self, ...) -> Self + ...; where Self is the BootstrapServerBinder
Run into troubles in the loop streaming bootstrap information. Would require the methods to take ownership of the binding for each iteration.
#3811 compiles and passes. It uses a non-handshaked binding, then turns into an actual binding with the handshake method.