Why Are the Bridges Burning
LisCon 2021 · 20 Oct 2021 · 18:30
James Prestwich, credited with Optics, speaks at LisCon 2021 in Lisbon. The talk, titled Why Are the Bridges Burning, asks why cross-chain bridges are running into trouble.
Speakers
Topics
From LisCon 2021, hosted by LisCon.
Transcript
all right uh let's get going i'm gonna try to get through a lot of material very quickly uh for you know people who don't know me already my name is james prestwich i am a protocol designer and kind of cross chain engineer i've been working in the cross chain space for almost five years now um so i started off working on atomic cross chain transactions with bitcoin and ethereum and um you know i've done a bunch of things with tbtc with cross chain bridges and you know what i want to talk to today is why are the bridges burning uh when we talk about crosstrain bridges
we've seen a bunch of hacks we've seen a bunch of lost money what is going on that is making these bridges fall apart in order to do that i'm gonna have to talk a little bit about you know what is a bridge uh how do they work what's the mechanism underlying them why do the layers fail uh so throughout the talk i'm going to be using standard flowchart terminology uh the rounded rectangles are start and end states the little boxes are steps the diamonds are decisions the parallelograms are input and output to the process any diamond that only has one whisker out uh assume that the other whisker means that everything falls apart and
the bridge breaks and we don't go across chains today so bridging blockchains what is a bridge the the problem here is that you have bitcoin and you want to use it in depths or you have ether and you want to take it to solana uh we need to make something that goes in the middle that takes information from one chain brings it to another chain in order to do that we want to lock up our each on one chain we want to mint west on the other chain and we want to use it in dapps over on solana or bsc or whatever and then we want to be able to get it back we want to be able to burn that west the representation on the remote
uh and get our eath back on ethereum so this is you know what makes it a bridge is the application is the minting and burning the supply management uh saying that at any given time we haven't increased the amount of ethan circulation even across multiple chains uh we ensure that the mint corresponds to the lock and the unlock corresponds to the burn and in order to do that we need to you know cross this boundary between chains uh we need to get info from one chain to another and to do that we use one-way communication channels uh so we would have a communication channel from ethereum to cello and a
communication channel from cello back to ethereum and that's the only way to do this bridges are what we call dual simplex which means they simulate two-way communication using two one-way independent channels it is actually impossible to build a duplex channel and a blockchain for reasons we'll talk about in a second uh so you know we have this intuitive understanding of bridges we want to preserve supply integrity across multiple chains we need to send information about the supply of ether from one chain to another and then send it you know information about the supply of ether on that chain back when we want to unlock our ether uh in order to do that we need a
cross-chain communication mechanism and there are tons and tons of choices for these uh and everybody just uses trusted multi-sigs uh we have like five different options available and everybody just loves so we we can dig into this a little more obviously we have one-way communications we want to just send information from one dap on one chain to another dap on the other unfortunately we have these barriers between chains we can't just you know send info from one chain to another this just doesn't work you can't have the message received automatically
so what we need to do is we need to introduce a few more steps uh we need to have the receiving chain process a transaction that came from the sending chain when we're sending info from one chain to another the only way to get info into the receiving chain is to make a transaction so we have to have the sending chain dispatch a transaction unfortunately we can't do that either because blockchains aren't users and they don't have private keys so blockchain can't sign a transaction for another blockchain so you can't send a transaction from one blockchain to another so we need to introduce you know a bit more complexity the thing we actually do in practice is
we have the sending chain commit the message so it commits to the burnt ether or the locked ether uh some off-chain actor some like person running a server somewhere sees that message decides to forward it to the other chain and signs and dispatches a transaction so some off-chain trusted third party has to sign and dispatch transactions in any cross chain system uh it is not possible to have a chain just dispatch a transaction to another you need to introduce a reliance on an off-chain semi-trusted party because chains are passive they can't
reach outside themselves and affect the world they can only update their own state um communication on the other hand has to be active we need to send this message and we need to be sure that it's going to get there and so in order to resolve that problem we need to introduce communication channels and off chain actors that's how we cross the truss boundaries so so let's get to the kind of fun part of the talk where i'm gonna be spending a lot more of my time uh layers uh how do bridges break you may have uh you know like seen this life cycle about 30 seconds ago on another slide
um we need to you know go through seven concrete steps in order to get a message from one chain to another a lot of these steps are not very reliable or uh difficult to engineer so you probably have heard of thor chain uh a few months ago thor chain lost eight million dollars which i mean in the blockchain space is not that much money i guess uh thor chain lost eight million dollars uh when somebody broke their bridge um and in order to explain why i gotta walk you through a little bit of ethereum transaction processing how does an ethereum transaction hit a
smart contract cause other calls and get processed how did thor chain break it broke in the commit and off chain actor recognition of a message and we're gonna talk about why ethereum processes a transaction starting from a user who calls a smart contract with some money and some data and that smart contract might call another smart contract with money and data and another in another and you can go in you can fire off events which externalizes information so that off chain actors can see it and when smart contract 3 is done it returns data to smart contract 2 which returns data to smart contract one which you know returns data back to the user
so you actually get really deep call stacks in any complex validity application instead of one to three smart contracts we're probably interacting with 6 10 15 smart contracts on any you know relatively complex transaction uh and what this means is that it's very difficult to write code that correctly observes unwinds and parses an ethereum transaction to figure out what actually happened uh once you've gone through like you know call stacks 10 deep it's difficult to just like know as a human and to know as a developer how to process what happened so thoughtchain
wrote a huge ethereum transaction parsing library in go uh and it's part of their node software and it is what all of the multi-sig signers run when they're moving all of the money and thor chain around uh and what it does is it looks at an ethereum transaction and it looks for an event fired by the thor chain cross chain contract it looks for an event that says how much ether was sent you know how much ether is supposed to go over the bridge it processes that event it issues that ether over on thor chain and does whatever it's supposed to do so the way thor chain broke
is that a user inserted a malicious contract into the stack the malicious contract kept all of the ether did not forward any value to the thor chain smart contract system and you know sent the ether back to the user at the end of the transaction but due to a bug in their transaction processing system uh instead of reading zero value in the event from the smart contract the thor chain system you know thor chain chain uh read the value that was initially sent in the transaction so they read tx.value instead of the transaction receipts
logged out value and it's really interesting because if you read their code the buggy code they actually read the correct value they read the zero value first and then they later go back and overwrite it with the incorrect high value and this allowed a user to fool the bridge into thinking that ether had been sent when in fact the user got to keep all of their ether and so this user issued themselves eight million dollars worth of ether on the thor chain chain and swapped it into something else and took it all back and you know walked away with a few million dollars uh it is very difficult to like spot these transaction processing bugs because again the call stacks in these are incredibly complex and nobody's very good at this
thoughtchain broke in the part of the stack that commits the message and has an off-chain actor see the commitment uh they committed the correct message and then the off-chain actor read an incorrect message uh so the part of the stack that broke for thor chain is you know this big orange bubble right here everything else worked perfectly and the moral of the story is that chain vms are hard and taste bad if you are writing custom ethereum transaction parsing and tracing logic you are doing something very wrong you are doing something bad and you should stop doing that uh chain specific handling is
error-prone it's complex it's uh arcane this uh issue is like a thousand lines deep into a dot go file where no one has ever looked except the developers um we should not be writing chain specific parsing if we are you know relying on ethereum to do our work for us we should rely on the event or the state and nothing else never do transaction tracing and if you are designing a cross chain system do not design it in a way that relies on transaction tracing or call stack management or anything like that it's very bad and you're going to ruin it okay chain specific logic should be on chain chain specific logic shouldn't be
in the off chain actor because you're gonna wreck it you're gonna mess it up it's bad okay so the other one that i want to talk about that is also really interesting uh is poly network not poly market that's a completely different product poly network lost 600 million dollars of user funds and for me at the time i was like how is there even a bridge that i have never heard of that has 600 million dollars in it uh it was shocking uh so this happened again a few months ago earlier this year uh the funds were eventually returned by the attacker sort of after someone threatened to dox them and there was a whole lot of like really
interesting drama uh it's a great story uh you should go look it up but i want to talk about the the technicals is how did poly network break uh they broke in a completely different part of the cross chain stack uh they actually broke in the transaction handling on ethereum so again uh in ethereum we're going to use the call stack and we're going to talk about how poly network specifically routes incoming cross-chain messages when the poly network crosstrain contract receives an incoming message it's got the recipient contract the data the value etc
and what the polynetwork system is supposed to do is take that incoming relayed cross chain message and forward it with the data and the value to the recipient this is some user specified smart contract uh so for example an incoming polynetwork uh message might be instructions to call compound with a specific blob of data and a specific amount of ether um and so the off train actor takes that message uh gives it to the system contract the system contract unpacks it and sends it on to compound so the way poly network broke is that
the user didn't specify compound they specified the poly network bank and the way poly network is set up is that the treasury where all of the cross chain funds are held is owned by the system contract of course you know it's the system it owns the treasury so the user had the system unpack this cross chain message send it to the poly network bank the polling network bank sees that it's being called by the system and assumes that the system has admin privileges and so all the user had to do was politely ask for all of the money uh just send a cross-chain message saying please give me all of the money and the poly network system obligingly forwarded that message to the bank the
bank says oh the system wants all of the money i'll just go ahead and forward all the money so this is why uh cross-chain communication needs strict layers it's why we make this separation between the communication channel and the handling layer violation here is that the bank is owned by the system and the user can give the system arbitrary instructions coming in over the cross-chain communication channel there's no distinction between local transaction processing and remote and in order to add that distinction we need to make strict layers we tend to use the concept of a router is there's a cross-chain channel it's
like an ethernet cable you plug it into your router and those are extremely separate things so poly network because they have this confusion between local messages you know like the poly system moving around funds locally and remote messages user-defined calls that are coming in from a remote chain coming in over the wire any user could take all of the money at any time and it just you know took a few months and 600 million dollars for someone to notice this so we want these layers we have cross-chain communication channels we have cross-chain applications they need to be strictly separate
app logic needs to be separate from channel logic this has some side benefits for example if app logic and channel logic are separate it means you can swap out the channels at any time or you can update the app logic without updating the cross-chain communication logic uh polynetwork was not able to do that and although they did get i think most of the funds back eventually it took a lot of time a lot of off-chain action and you know action from the trusted poly network operators uh it is like not uh it is unreasonable to have this kind of layer violation in 2021 when we have known how to write networking stacks for
30 years or more i guess networking stacks 40 or 50 years huh this is normally the time in my presentation when i would break for questions it feels like this is going to be really difficult to do in this environment so i'm going to wrap up here and i will be around the conference if you have any questions if you have you know two takeaways from this talk it's that you should never write chain specific processing uh you should never try to parse an ethereum call stack you should never do transaction tracing if your bridge relies on that it's going to fall over and burn and if you are writing an application you need to make a strict separation
between application logic and infrastructure logic and confusing those will allow users to have you know well privileged escalation these are classic errors from you know 30 years ago that we have reintroduced in a new context because we just didn't learn the history uh so thanks for the time i'm gonna wrap up and feel free to find me around the conference and ask any questions [Applause]