New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Loading player…

Unlocking the Past: Building Trustless dApps With Relic | Tim Becker - ChainLight

Ethereum DenverWed, Oct 9, 2024, 12:00 AM

Thanks to zkSNARKs, it is now possible to cryptographically verify historical state on-chain. This makes state such as past account balances, storage slots, or log emissions trustlessly accessible by smart contracts! We will discuss how you can build your own dApps to use this superpower. APPLICATIONS FOR ETHDenver 2024: #YearOfTheSpork ARE OPEN APPLY NOW https://ethdenver.com/apply

Transcript

[Music] name is Tim Becker and I'm a researcher at chain light and today I'm going to talk about Relic protocol and how you can build onchain applications that access historical state from both L1 and L2 um and because that's not a very creative talk title we had in llm come up with our actual title which I think turned out pretty well um yeah so we'll start with the fundamental problem that we're trying to address here which is that onchain data access is very limited so from Smart contracts you can basically access a subset of the current state of the chain so this includes all of the account balances um your contract storage mappings and of course you can call other contracts and you know get results from their functions but you cannot directly access the state mappings of other contracts TR s and you know some will say that this is for a good reason like data encapsulation and all that stuff but I would argue that more often than not this is not for a good reason either it's an oversight of the the contract developer where they didn't see a use case for this exposing this data or it could be to reduce the size of the contract so that you know it fits under the code size limit of ethereum or whatnot um another huge set of data which you cannot access are log emissions so offchain we take this completely for granted you know most um indexers offchain uh rely basically entirely on log emissions but from Smart contracts you actually have no way to access this set of data and so if some onchain interaction happened that only emitted a log or maybe the most convenient data format was in a log uh there's no way for you to access this onchain um and yeah more generally you can't access historical state of any kind so even if something was in storage even if it was in your own contract storage but five blocks ago there's no good way to access that so this is kind of the problem we're trying to solve and just as a simple motivating example we can say what if your contract wanted to know who owned this pudgy Penguin at block 15 million so this is a very simple question you can ask an RPC provider like infura or Alchemy and of course you can also query any archive node and they'll be able to answer this question for you very easily but if you were to pick a random node on the ethereum network you would instead get this horrible error message about some missing TR node and it will completely fail to answer this question and the reason for that is that on ethereum old data is pruned away for most nodes it's only required that nodes keep the current state of the chain and so um any once the data gets old enough and is finalized um most nodes will prun it way to reduce dis space and uh make it easier to run nodes um but if you look at how this data is actually stored so basically everything of interest is either in the block header or in a mer p a try which is committed to by the blockader uh and this includes all of the account balances all of the storage transactions logs everything um and because it's in this merel Patricia Tri which is kind of like a Mer tree you can generate very proofs of any data in the tree that you want relative to the size of the tree so even if there's hundreds of millions of ethereum accounts it only takes like a few kilobytes of data to prove information about any one of them um and yeah you can actually ask any archive node and most RPC providers to generate you these proofs um and here for instance we're asking who owned that pudy penguin and it'll give you all the data you need to verify that at that block BL this was the owner of that pudy penguin and so what does verifying these proofs look like um it's actually just dominated by Computing a few cat hashes which is really not very expensive and in fact it's completely cheap enough to do on chain so you know the depending on what kind of data you want to access the cost will range from On The Low End like the equivalent of an erc20 transfer and on the high end it'll be maybe more like a deck swap but these are completely reasonable gas costs that you know for some applications make perfect sense to do on L1 and of course if you're on L2 these gas costs make even more sense um and we'll get to some more stuff about L2 shortly so this actually glosses over one small issue which is that from your smart contracts you don't actually have a way to get all of the historical block hases so the evm only gives you direct access to the last 256 block hashes and if you want older ones of course you can verify them by unrolling the blockchain by providing all of the intermediate headers from one you can verify back to what you need um but of course this is way too expensive to do on chain and even offchain honestly because the cost is linear in the age of the block so if you want a million blocks ago you have to compute a million block hashes basically um so there's a better way to solve this problem which is to basically do this unrolling of the chain only one time and do it in a ZK snark so what you can do is you can take a sequence of consecutive block headers uh and in a ZK snarc you can compute all of their block hashes and verify that they are correctly linked to one another by looking at the parent hash field and then you take all of these block hashes and you build a Merkle tree of them and what you put on chain is only this this Merle rout and and the proof that all of this is valid and then by caching this mer rout on chain um you can quickly verify any historical block has by simply doing a a short Merkle proof of all the block hashes you don't need to do the whole unrolling and uh link verification anymore so yeah um just to really emphasize this point this is a onetime cost that you do up front at the start and then you're able to access historical blashes very cheaply on chain so then what about l2s so there's actually two questions here one is um reading L1 data from L2 contracts and this is actually very easy because l2s are able to trustless read L1 data um at least most of them and so we can use exactly the same scheme and give L2 contracts access to all of the historical L1 data and you know this makes it extremely cheap to do basically any sort of uh use case which we'll get to in a moment um the other question is what about L2 contracts accessing historical L2 data and this is a little bit harder because the block times on l2s are a lot shorter and so the sort of the costs of doing that ZK verification are proportionately higher but um new ZK proof systems may make this like completely feasible in the near future but um I also want to highlight another partial solution which is we can use the ability to trustless read L1 data to actually read the state roots of the l2s that get posted there on the L1 and use those to access L2 data so this is basically like a near zero cost solution to get L2 contracts to access historical L2 data so yeah I mean this kind of solves the problem of historical data access on L1 and L2 and this is basically the scheme we've implemented for Relic protocol which is uh onchain protocol for accessing all this historical State um we have sdks for proof generation which are JavaScript and typescript and verification which are solidity and so it kind of abstracts away all of this logic about the verification and generation that's somewhat complicated so developers can just focus on the use cases for this data don't need to worry too much about what's going on behind the scenes um Relic is built with immutable modular contracts so we thought really hard about like forward compatibility and how to minimize trust so I'll talk about that more in a moment but um there's not really many trust assumptions being introduced here and uh yeah so we've been on L1 for a year and a half or so and we recently deployed on l2s including ZK sync era optimism and base and the optimism base support is basically optimism Bedrock support So any chain that builds on that platform will be able to support very easily so you may Wonder like why isn't this just a library like why do we actually need a protocol why do we need like common contracts and there's two main reasons for this the first one is forward compatibility so because like getting at this historical data requires digging into the internals of ethereum there's always the possibility of breaking changes happening so uh one major one are veral trees if those are implemented in the future that'll swap out the merco Patricia tries for a completely different scheme and so the way that you verify data is going to have to change um another thing is uh new features and new optimizations so EIP 4788 is coming in the denune hard fork and this gives the execution layer access to the beacon State Route and so using this you can access all of the beacon data as well um but also this actually unlocks a cool like optimization for accessing execution layer data as well and this is kind of out of scope of this talk so I won't get into the details but the fact that ethereum protocol updates and you know there's breaking changes or new features means it's nice to have a convenient like uh one you know like one location where you do these upgrades um yeah but I want to emphasize that any projects that use Relic are completely in control of like which version of these verifiers they want to trust so there's no like you know forcing any updates or anything like that um yeah the other major reason why this isn't just a library is cost amortization so you know this onetime cost of doing all the ZK proving and any sort of like intermediate proof data that uh multiple people want to access can be cached and so the costs of proving all of these things can be amortised across everyone who uses it and so this basically just makes it cheaper for everyone who wants to access historical data so I want to highlight a couple of use cases that we envision for this um one kind of obvious one are airdrops so most airdrops as you know are based on onchain activity and usually the way it works is the project organizers will sort of index all of the stuff that happened on chain determine who is eligible for the airdrop meriz all of those um claims input them on chain for people to claim um and in many cases this is just a very simple transformation and so it's trivial to just instead write this as a A system that uses Relic to basically onchain directly verify that the user performs some onchain action and is therefore eligible for the air drop um yeah another huge category is governance so because we have the ability to access data at some fixed Block in the past we basically get free onchain snapshot voting so um it's you know somewhat expensive to do onchain voting but because we have the ability to do this on L2 and reference L1 data you can actually do all of the voting on a jeap L2 do all the vote aggregation determine the result and and trustly send that back to L1 for your proposal to be executed so uh yeah instead of being dollars per vote it's pennies per vote and um it makes onchain governance very practical um another really cool use case are voting pools so I want to shout out Federation here which was one of the first projects that built on Relic uh it's an nouns Dow ecosystem project and what they did was build a governance pool where people can delegate their nouns votes to a Smart contract and then this um voting pool is controlled programmatically and in their case it was actually like auctioned off and then all of the people that delegated to that pool were able to claim their portion of the winning bid um which was really cool uh another use case category is reputation and identity so using something like Relic you can prove any historical onchain action and tokenize it as a soulbound token and then you can integrate that with any existing um identity ecosystem but you can also do like feature gating or like provide special perks to users that have high reputation or that can prove that they participated in some like previous actions in your project um and kind of our like uh proof of concept in this category is a um onchain birth certificate so you can prove like when your ethereum count was created the first block that was created and um tokenize that as a soulbound token uh which has some cool like onchain generative art that we did um and yeah the final category I want to highlight are oracles so um using this you can build a trustless Oracle for anything that's on chain so you know even if a project didn't intend for their price feeds to be an oracle you know they didn't like integrate a tww or something like that um you can use this to get at that data and produce an oracle from it and this is completely trustless so it doesn't rely on you know anyone relaying prices and another really cool thing is that because you can read L1 data on L2 you can bring any Oracle that's on L1 and access it from L2 so that Oracle doesn't need to explicitly support that L2 you can just as soon as the price updates posted on the L1 you can instantly access it on the L2 and you just kind of inherit all the oracles from L1 so yeah those are just a few examples um if anyone has ideas for other cool things you can do with this we'd love to help and support your project um you can find our docs here join our Discord follow us on Twitter um yeah be happy to take any questions if there are some [Applause]

Automatic transcript — names and jargon may be misspelled.