How to build a custom EL on reth with minimal footprint #16067
Replies: 3 comments 4 replies
-
hey @roberts-pumpurs thanks for the write up.
this is currently still the case yes, the optimism folder would be the blueprint for We definitely have some work to do and are focusing on this next to makes this easier and reduce boiler plate as much as possible, e.g. by relaxing some bounds on the default eth/op types. from experience, introducing feature flags is a nightmare to maintain, but it would be the fastest way to get something modified. while we're trying to make some modifications possible directly in reth. My recommendation rn would probably be some kind of hybrid approach, where you start your chain as new standalone repo/crate but use a fork of reth as dependencies, this way, if you encounter a limitation you could flag this to us so we can address but in the meantime you could modify something in place, e.g. via feature flags.
what worked well in the past is a cycle of
this is basically how the opstack support evolved In the meantime we'll be making simplifcations to the common: The custom-node example is also still actively being worked on and got some upgrades over the last few days, we want to use this to find limitations and improve UX specifically for this use case. I ack that this currently requires a lot of boilerplate, but gives you the most flexibility in the long run. |
Beta Was this translation helpful? Give feedback.
-
Just ACKing that this is explicitly a design goal of the Reth SDK work -- so we'll make it work. Thanks for flagging it. Please get more of your friends to share their feedback / design directions in this thread. |
Beta Was this translation helpful? Give feedback.
-
As a brief update here: we ended up hijacking legacy transactions with custom data payloads & system specific validation rules (i.e make sure custom data payloads are only accepted in certain cases). you can see the implementation here |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
We are building a L1 blockchain that would use reth as its EL. We need ways to "decrement" user balances based on stuff that happened on the CL. After discussions on Telegram, @mattsse recommended to base our solution on the Reth-Optimism approach by introducing a new transaction type with custom processing logic that only the CL could inject into the mempool.
Our ideal integration with reth would be:
After a lot of experimentation last week, here's the summary of where we currently stand:
custom-node
example to our repo and making adjustments. Thecustom-node
example in Reths repo just proxies types and implementations toreth-optimism
, making this approach a fools errand. Not all the files fromcustom-node
example were actually used in the actual implementation; eg theExtendedTxEnvelope
was unused anywhere outside of theextended_op_tx_envelope.rs
module. Essentially, the example is insufficient/unfinished to be used for our needs, hard-to-understand compile errors made this approach unfeasible, as I was hoisting out a lot of code into our repo, just to make some adjustments & trait implementations. This turned out to be a massive undertaking. Because the deep, nested layers of generic meta-programming, to me it was never really clear what other trait must be implemented or which constraints are needed. We'd need someone on the reth team as a guide for this approach. Altho this would give us the smallest surface area and the least amount of code that we'd need to own and maintain. The breaking point was after I introduced our own custom node primitive struct.ethereum
subfolder and making adjustments, renaming types with our prefixes. The goal was to have a minimum eth-compliant node, with its default implementations inlined in our repository, and then we'd just make alterations where necessary. This approach faced the following problems:ethereum
folder is not a self-contained Ethereum implementation of all the necessary traits & types. I could not properly use our ownPrimitiveTypes
. We ran into problems whererust_ethereum_primitives
were hard constraints on some trait implementations (like LoadReceipt) that were not even located under theethereum
folder. This cascaded into the following loop: get compile error about X not satisfying trait constraints (because of some custom primitive we've renamed), copying over the reference implementation and making alterations so it uses the new primitive definition, repeating. As an end result, I was again hoisting over unknown amount of code from crates that lived outside of theethereum
subfolder (from reth core implementations), and making adjustments so it'd use my primitives. Also, such an approach is not documented and seemed like another fool's errand because there was no end in sight of how much stuff I'd have to copy & alter, and whether whatever I was copying was actually a necessary change, and if it would even work once all was copied.ethereum
folder (eg custom txpool crate is self-contained there) - it seemed like a more complete version. Also, because our custom eth EL would ideally add a new custom transaction type and work on users balances, the Optimism code would be a very close fit for what we need. Goal being: rather than having "ethereum + our changes", I'd have to do "optimism - unnecessary stuff". But this approach also has its own issues. Namely, optimism heavily depends on optimism-alloy crates (with which I have no experience and I wouldn't know what extra stuff would I be bringing into my dependency chain), and other crates within reth withoptimism
orop
feature flags. As an end result, after hoisting out all ofoptimism
folder, renaming the crates & types to our own, the dependencies would still point toreth
crates withop
feature flags (egreth-primitives-traits
withop
feature), and these crates would then depend on thereth-optimism-primitives
& friends rather than the forked version I had in my repo. Only 2 options available: use[crates-io.patch]
to force these internal dependencies to use my custom crates that I've forked fromoptimism
folder, or start hoisting out all of these reth-core dependencies into my own repo and adding changes there, and eliminating all usage ofop
feature flags. Either way both approaches seem either brittle or like an insane amount of work. Especially if I'll then have to cut out a lot of logic that optimism does (eg sequencer comms) and other stuff that I may not even be aware of.CONCLUSION (TLDR): A common pattern in all of my attempts is that I end up copying over large amounts of code from reth core crates (stuff that did not live under the
examples/custom-node
, norethereum
, noroptimism
subfolders). And making adjustments to those. Eg when hoisting outreth-optimism
I was suddenly an owner of 16k LOC that I did not even write, and still could not get my solution to compile. Arguably a skill issue on my end tho 😄 . I am just highlighting my experience, hats off to you for writing a generic Ethereum EL.QUESTIONS:
my-custom-chain
(eg copying over theoptimism
folder) and keeping all of the changes there, optionally adding feature flags to reth core crates (in a similar fashion likeop
feature flags). Then the only maintenance burden would be my own subfolder and keeping my reth fork in sync.Beta Was this translation helpful? Give feedback.
All reactions