@proto-kit/module
v0.1.1-develop.1088
Published
Set of APIs to define YAB runtime modules and application chains.
Downloads
398
Readme
YAB: Module
Set of APIs to define YAB runtime modules and application chains.
Application chain consists of multiple runtime modules. Runtime modules can be either implemented as part of the chain directly, or imported from 3rd parties. Here's an example of how a chain with two runtime modules can be defined:
const chain = Chain.from({
state: new InMemoryStateService(),
// specify which modules should the chain consist of
modules: {
Balances,
Admin,
},
});
// compile the chain into a verification key
const { verificationKey } = await chain.compile();
Chain works as a wrapper for all circuit logic contained by the runtime module methods. Compilation produces a wrap circuit including all known methods of the configured runtime modules.
Here's an example Balances
runtime module:
@runtimeModule()
export class Balances extends RuntimeModule {
@state() public totalSupply = State.from<UInt64>(UInt64);
@state() public balances = StateMap.from<PublicKey, UInt64>(
PublicKey,
UInt64
);
public constructor(public admin: Admin) {
super();
}
@runtimeMethod()
public getTotalSupply() {
this.totalSupply.get();
}
@runtimeMethod()
public setTotalSupply() {
this.totalSupply.set(UInt64.from(20));
this.admin.isAdmin();
}
@runtimeMethod()
public getBalance(address: PublicKey): Option<UInt64> {
return this.balances.get(address);
}
}
The Balances runtime module shows how the YAB runtime module API can be used:
runtimeModule()
- marks the class as a runtime moduleclass Balance extends RuntimeModule
- introduces runtime module APIs into the runtime module@state() public totalSupply = State.from<UInt64>(UInt64)
- defines a runtime module state of typeUInt64
, which can be either get or set@state() public balances = StateMap.from<PublicKey, UInt64>(PublicKey, UInt64)
- defines a runtime module map state, which allows values to be stored under keys, respective of the given key & value types.public constructor(public admin: Admin)
- injects a runtime module dependency to another runtime moduleAdmin
, which is a standalone runtime module@runtimeMethod() public getTotalSupply()
- defines a runtime module method containing circuit logic for a runtime state transition. Methods define how the chain state is transformed from the initial state to the resulting state.this.admin.isAdmin()
- shows how runtime module interoperability works, a configured runtime module is injected in the constructor, and can be used within the existing methods. Code of the called runtime module becomes part of the original method circuit (setTotalSupply in this case).
Method wrapper circuit
Every runtime module method gets wrapped into an extra outter circuit, which allows the underlying runtime to make assertions about the results of the method execution, such as:
- State transitions
- Execution status
- Transaction hash (method invocation arguments)
- Network state (TODO)
The good thing is, the YAB runtime module API does this for you automatically, but it pays off to keep this in mind when debugging your runtime modules. Due to the nature of the underlying ZK method lifecycle, methods cannot produce any side effects beyond the state transitions, which are implicitly generated using the State
API. Again due to method lifecycle implications, your method code will run multiple times at different stages of its lifecycle, such as:
- Compilation
- Simulation
- Proving
Please be careful about keeping your runtime module methods side-effect free, since it may introduce inconsistencies in the method lifecycle which may lead to the inability to generate an execution proof.
Testing
Runtime module methods can be ran or tested in two different modes:
- Simulation
- Proving
Simulation mode means that only the method javascript code will run, and no proving will be done. This is the fastest way of testing your module methods.
Provnig mode means that the whole chain needs to be compiled, and then every method execution can be additionally proven by accessing the provers generated during method simulation.
Here's an example of how a runtime module method execution proof can be generated, but please keep in mind you also need to enable proofs and compile the chain. More detailed examples can be found in test/modules
:
const chain = Chain.from({
state,
modules: {
Balances,
Admin,
},
});
const balances = chain.resolve("Balances");
balances.getTotalSupply();
const {
result: { prove },
} = container.resolve(MethodExecutionContext);
const proof = await prove();