-
Notifications
You must be signed in to change notification settings - Fork 302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tracking issue: Modularize the Penumbra application code into coherent crates #2288
Comments
One potential problem: currently, most of the |
part of #2288 later, it'd be cool to have each component define its own isolated state and have the penumbra-chain crate stitch them together
part of #2288 later, it'd be cool to have each component define its own isolated state and have the penumbra-chain crate stitch them together
Part of #2288. This is a proof-of-possibility for the architecture described in that issue. Now, the `penumbra-shielded-pool` crate is self-contained, with both the on-chain structures required to track the shielded pool, and the transaction actions needed to interact with it. In the future, a fair amount of functionality currently in the `penumbra-crypto` crate could now be lifted up into this crate, for instance the definitions of the spend and output proof statements.
Part of #2288. This is a proof-of-possibility for the architecture described in that issue. Now, the `penumbra-shielded-pool` crate is self-contained, with both the on-chain structures required to track the shielded pool, and the transaction actions needed to interact with it. In the future, a fair amount of functionality currently in the `penumbra-crypto` crate could now be lifted up into this crate, for instance the definitions of the spend and output proof statements.
Closing as complete! |
Reopening, we also need to split into per component RPC implementations. I'll do that today. |
Updates the import paths for the `penumbra_proto` crate for compatibility with Testnet 61 Dione [0], specifically the work tracked in [1]. [0] penumbra-zone/penumbra#3046 [1] penumbra-zone/penumbra#2288
Added the follow-up issue #2914 to the checklist at the top. Once 2914 is done, we can close out this tracking issue. |
I don't think #2914 is related to this issue, it's definitely good to do but it's not part of modularizing our own code. |
Is your feature request related to a problem? Please describe.
Since there isn't already a Rust application framework for building Tendermint chains, we've had to build one at the same time as we've built out our application. This has been a messy and iterative process, and along the way, we've passed from having separate crates for separate components of the application (which turned out not to be entirely separate) to having effectively all of our application logic in a single crate, formerly called
penumbra_component
and now calledpenumbra_app
(after #2282).However, while looking at the current structure of our code, we realized there may be a path to re-modularizing it, not in a single stop-the-world refactor, but gradually peeling out chunks of functionality.
Describe the solution you'd like
The following plan is a sketch; the first steps are concrete and definitely a good idea, while the later steps are more speculative. As we do this, let's think step by step, and notice any unexpected frictions.
Change the
Component
trait so that theAppState
passed toinit_chain
is an associated type.This makes the definition of the
Component
trait independent of the rest of the Penumbra code. Later, it will allow us to split up the genesis state into per-component chunks, with each differentComponent
operating on its own definition of its genesis data. This avoids cross-component dependencies (e.g., component X has to know about component Y because the genesis data passed to component X has types from component Y).It might be worth delaying this until we can clean up the IBC code, which has a number of
Component
implementations that may not be necessary.Change the
ActionHandler
trait to add aCheckStatelessContext: Clone + Send + Sync + 'static
associated type.This makes the definition of the
ActionHandler
trait independent of the rest of the Penumbra code. MostActionHandler
s don't make use of the context, and could haveCheckStatelessContext = ()
. Others that do probably just use the anchor, and could have that specified as the verification context, rather than a fullArc<Transaction>
. This avoids cross-action dependencies (e.g., every action has to know about every other action, because it has to know about theTransaction
type that contains all of them including itself).Longer-term, this also presents some interesting opportunities. For instance, we could use the
tower-batch
strategy to create a context struct that had channels communicating withtower::Service
s performing batch verification of signatures and proofs.Pull the revised
Component
andActionHandler
traits out into a newpenumbra_component
crate.Once the traits don't depend on external traits, they can be extracted into a "bottom-level"
penumbra_component
crate that only depends on thepenumbra_storage
crate, and no other Penumbra workspace crates. Ideally, thetower_abci
+penumbra_storage
+penumbra_component
stack would be useful to third party teams building Rust blockchains.Peel components out of
penumbra_app
into individual crates, bottom-upOnce the
Component
andActionHandler
traits are in a bottom-levelpenumbra_component
crate with no Penumbra-specific dependencies, we can peel components out into individual crates, bottom-up. Some initial refactors might be:sct
andcompact_block
"pseudo-components" intopenumbra_chain
, which can now depend onpenumbra_component
;penumbra_shielded_pool
crate with the shielded pool component;penumbra_ibc
crate with the IBC component.This will force us to declare each component's public APIs and the dependency relations between components. Along the way, we may discover dependency cycles among some of the higher-level components, which we'll need to resolve. The structure we're aiming for is one where we have a top-level
penumbra_app
crate depending on its individual components, each in separate crates containing theComponent
impl, andActionHandler
s for relevant messages.Updated subchecklist:
penumbra-shielded-pool
penumbra-ibc
penumbra-dao
penumbra-stake
, includingDelegate
,Undelegate
,UndelegateClaim
,ValidatorDefinition
actions (move theIsAction
impls totransaction/src/is_action.rs
for now)component
module feature-gated by acomponent
feature;app
intocomponent/action_handler/
component::metrics
module, withregister_metrics
publicly re-exported fromcomponent
component::state_key
.crate::event
module (can be empty if we don't have events defined)transaction
crate to update the location of the actionspenumbra-dex
Swap
,SwapClaim
,Position*
actions (move theIsAction
impls totransaction/src/is_action.rs
for now)component
module feature-gated by acomponent
feature;app
intocomponent/action_handler/
component::metrics
module, withregister_metrics
publicly re-exported fromcomponent
component::state_key
.crate::event
module (can be empty if we don't have events defined)transaction
crate to update the location of the actionspenumbra-governance
Proposal*
,ValidatorVote
,DelegatorVote
actions (move theIsAction
impls totransaction/src/is_action.rs
for now)component
module feature-gated by acomponent
feature;app
intocomponent/action_handler/
component::metrics
module, withregister_metrics
publicly re-exported fromcomponent
component::state_key
.crate::event
module (can be empty if we don't have events defined)transaction
crate to update the location of the actionsAlign protobuf package organization with new Rust code organization
All of the preceding moves only affect Rust code, but leave the proto packages unchanged. Once we have a coherent organization of the Rust code, we can update the proto packages to mirror it. This also allows us to define per-component GRPC methods.
Align gRPC services to match new crate-aligned proto organization - ibc: split up query rpc implementations #3079
Lift functionality out of the
penumbra_crypto
crate into component crates.Similar to the
penumbra_app
crate, thepenumbra_crypto
crate has likewise become a catch-all for everything not involving the state machine. But once we have components in individual crates, we can lift functionality out of thepenumbra_crypto
crate, this time working top-down. An initial refactor might be lifting thedex
module up to thepenumbra_dex
crate. Eventually, at the bottom, it would be nice to haveNote
s defined as part of thepenumbra_shielded_pool
crate.At the end, we'd end up with a stub
penumbra_crypto
that just had the key hierarchy and some core numeric types likeAmount
orU128x128
, which could potentially be renamedpenumbra_keys
or something. Each component crate would have the structures andAction
s relevant to that functionality, aligned with the corresponding proto package, together with any proof statements for those actions and the application-side logic implementing theComponent
andActionHandler
traits. To make this work, we'd need each crate to have acomponent-impl
(or similar) Cargo feature that would feature-gate the server-side logic and async execution, allowing client code to import the data structure definitions and client logic without having to pull in Tokio and other dependencies that might not be desirable everywhere (e.g., wasm). It might also be useful to feature-gate the proofs behind aproof-impl
Cargo feature for similar reasons.The text was updated successfully, but these errors were encountered: