State Machine Client
Now that we have a way to verify the consensus proofs of a blockchain in a fully byzantine fault tolerant manner. We might like to read the state of the blockchain. This allows us to execute any outgoing requests addressed to us, stored in the state trie of the counterparty blockchain. In order to read the state of the blockchain we’ll make use of state proofs. Different blockchains may adopt different kinds of state tries. eg Merkle-patricia, IAVL, Verkle tries, Binary merkle trees, whatever the case may be, it is also the responsibility of the consensus client to provide the ISMP framework with an implementation of the StateMachineClient
.
The state machine client is an abstraction over the state proof scheme of a given state machine. By decoupling the ConsensusClient
from the StateMachineClient
which are typically combined to form a light client, the ISMP framework allows a consensus client to support multiple state machines, each potentially using different state proof schemes. This abstraction makes ISMP future-proof, enabling deployment on both monolithic and modular blockchain architectures, including Polkadot, Ethereum, and others.
/// Convenience enum
pub enum RequestResponse {
/// A batch of requests
Request(Vec<Request>),
/// A batch of responses
Response(Vec<Response>),
}
/// Proof holds the relevant proof data for the context in which it's used.
pub struct Proof {
/// The state machine identifier
pub id: StateMachineId,
/// the corresponding block height
pub height: u64,
/// Serialized proof
pub proof: Vec<u8>,
}
/// A state machine client. An abstraction for the mechanism of state proof verification for state
/// machines
pub trait StateMachineClient {
/// Verify the overlay membership proof of a batch of requests/responses.
fn verify_membership(
&self,
host: &dyn IsmpHost,
item: RequestResponse,
root: StateCommitment,
proof: &Proof,
) -> Result<(), Error>;
/// Transform the requests/responses into their equivalent key in the state trie.
fn state_trie_key(&self, request: RequestResponse) -> Vec<Vec<u8>>;
/// Verify the state of proof of some arbitrary data. Should return the verified data
fn verify_state_proof(
&self,
host: &dyn IsmpHost,
keys: Vec<Vec<u8>>,
root: StateCommitment,
proof: &Proof,
) -> Result<BTreeMap<Vec<u8>, Option<Vec<u8>>>, Error>;
}
verify_membership
Since the ISMP framework permits the the IsmpHost
to persist the outgoing requests and responses in an overlay tree. The StateMachineClient
must provide the verification algorithm for this overlay tree through the verify_membership
method. If the host is unable to leverage an overlay trie, then this method will simply verify the state proofs of requests and responses.
state_trie_key
The ISMP framework does not enforce where requests & responses should be persisted in the state trie and allows state machines to store them wherever they like provided that they can describe a path to the request/response committed in storage given the full request/response.
verify_state_proof
Given a StateCommitment
, an arbitrary set of keys and a state proof, this method should perform state proof verification and return the verified values for provided storage keys. These keys may point to an empty leaf and as such should be represented with Option::None
. This signals a non-membership proof for the provided keys which is used in request timeouts. State proof verification is also used in handling Response::Get
in order to verify the storage values requested in the Request::Get