Sovereign-Labs / sovereign-sdk

A framework for building seamlessly scalable and interoperable rollups that can run on any blockchain
https://sovereign.xyz
Apache License 2.0
364 stars 104 forks source link

Consider using rollup-interface `Zk/Prover/StandardConfig` types in Context trait #375

Open preston-evans98 opened 1 year ago

preston-evans98 commented 1 year ago

Background

Currently, we embody the separation between Zk and Native execution in two ways. First, we have three zero-sized structs defined in rollup-interface which implement the sealed StateTransitionConfig marker trait. (The three structs are ZkConfig, StandardConfig, and ProverConfig. We use these structs to parameterize the StateTransitionRunner trait - and in an upcoming commit, we will also use them for the BatchBuilder trait.

The second place that the distinction between modes shows up is in the Context trait from the module system. Currently, devs can users adjust their cryptographic operations by switching from (say) ZkDefaultContext to DefaultContext. However, the current implementation is a bit clunky, because the type system doesn't enforce that you always combine the correct contexts together. For example, if we had another type SomeOtherContext, there would be nothing to prevent a developer from accidentally using DefaultContext native mode, and SomeOtherContext in zk mode.

We should consider introducing the StateTransitionConfig types into the Context trait. This would solve two problems. We wouldn't have two different sets of types for dealing with the zk/native distinction, and we could use the type system to make the connection betwee DefaultContext and ZkDefaultContext.

Implementation Sketch

The final implementation would look something like this:

pub trait Spec<T: StateTransitionConfig> { 
  // elided
}

pub trait Context<T: StateTransitionConfig> { 
  // elided
}
pub struct DefaultContext<T: StateTransitionConfig> {
  // elided
}

impl Context<StandardConfig> for DefaultContext<StandardConfig> { 
  // elided
}

impl Context<ZkConfig> for DefaultContext<ZkConfig> { 
  // elided
}
// in the stf
pub type DemoApp<Conf, Vm> = AppTemplate<DefaultContext<Conf>, Runtime<DefaultContext<Conf>>, Vm>;
pub type DemoAppRunner<Conf, Vm> = AppTemplate<DefaultContext<Conf>, Runtime<DefaultContext<Conf>>, Vm>;
preston-evans98 commented 1 year ago

cc @bkolad

bkolad commented 1 year ago

If I understand correctly, the issue is that we have two ways of configuring a rollup at the type level, both serving a similar purpose, but there is a missing link between them. The proposed approach involves parameterizing the Context by a StateTransitionConfig, which establishes the link but introduces an additional generic parameter throughout the code.

Here is another proposition, we can create a separate trait in the sov-module-api module, called ContextFactory or DeriveContextFromConfig, as follows:

pub trait ContextFactory {
    type Context: Context;
}

Then, we can provide implementations for the specific configurations:

impl ContextFactory for ZkConfig {
    type Context = ZkDefaultContext;
}

and so one

Later, we can utilize this setup in the StateTransitionRunner implementation:

impl<Vm: Zkvm> StateTransitionRunner<ZkConfig, Vm>
    for DemoAppRunner<<ZkConfig as ContextFactory>::Context, Vm>{
...
}

Then we do it in BatchBuilder as well.

In this approach, we use a concrete StateTransitionConfig implementation at the top level (with BatchBuilder, StateTransitionRunner, etc), and when we need to use the Context, we derive it from the corresponding configuration type. This ensures that the Context is always correctly derived from the StateTransitionConfig, establishing the necessary link between the two. The drawback here is that we introduce another trait, ContextFactory, but its impact on the user's code should be minimal.

bkolad commented 1 year ago

Also the StateTransitionRunner already provides a soft link between the Config and the Context (The signature of this impl)

impl<Vm: Zkvm> StateTransitionRunner<ProverConfig, Vm> for DemoAppRunner<DefaultContext, Vm>