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

Loading player…

Solidity considered harmful - Vukasin Gostovic | Rainshower

ETH Belgrade CommunitySat, Oct 7, 2023, 12:00 AM

Transcript

thank you for the wonderful introduction uh so hi hello my name is uh I'll try to keep it short I have 30 minutes so you'll occasionally see QR codes on screen you can scan if you want to get more info so first of all uh who here knows how to program you can get okay cool awesome who here has written solidity who here enjoys working on large Solarity code bases amazing so uh evm works cool so uh DVM is a stack machine so it has transient memory and it has a miracle potential storage history so instructions get pushed onto it and then get it executed and a big misconception of how it works is that it's turning complete which is kinda true in production it's not we have the block gas limits so we cannot execute things perpetually we know that they have an end so solidity has a big identity crisis it tries to be a mix of java C plus plus and JavaScript it's designed to be easy and pick up and learn and this results in really poor ux as a solidity programmers generally have to fight with the language and have to resort to using inline yield for a lot of things so it's designed to be picked up easy to pick up alert as I said so uh it's great this is great for general purpose programming languages but solidity is not a general purpose programming language deviant is not a general purpose architecture in essence it's a glorified SQL database we're manipulating and solidity should be complementing that but yeah due to the approach of being easy to pick up and learn uh it's a very bad teacher and uh it doesn't work because it's designed to be for settlements so as I've said the evm is inherently low level so solidity should be complementing that by exposing users to low level language features but a lot of low-level language features that would make our lives easier or abstracted away so a great example of this is the type system so this disgusting code is used to extract data from device so uh solidity can only cast types of equal Sizer type so what we have to do is we have to convert this to base 20 and then do our arithmetic by converting that unit 160 then back to base 20 by 12 to equal cassette and then to uns32 so this kind of shows that like it's way too low level level to do an automatic cast and it's way too high level to deal directly with bytes so who here knows how to fix Point not fixed Point uh floating Point numbers work okay okay so uh floating Point numbers are used to approximate real numbers so and the most common implementation is ie754 where we have a significant a base and an exponent and we when we combine these three we get an approximation of a number so they're more tightly packed around zero and uh they are the approximations that are inaccurate we are approximating them so when we are used when we shouldn't be using them in applications where uh information accuracy is critical and the DVM doesn't have them so if I have an atom laptop and you have an x86 desktop there is a very good chance that my floating Point number would be different from your floating Point number so that would cause a cause a fork in a blockchain which is something we absolutely do not want and salinity doesn't offer us a native alternative and even though the Viper does solidity doesn't the excuse for this is that there is way too many implementations of decimal numbers so yeah they're kind of forced to use a drone or and or use third-party libraries which opens up to supply entries attack and of course implementation bugs so writing readable code is absolutely essential especially for this field where we're dealing with money settlements so proper formatting naming and code comments can give non-technical users an idea of what your code is doing which is pretty important and solidity is becoming less and less readable and I find that pretty concerning modifier this is going to be a spicy one so modifiers are used to amend the semantics of a function in a declarative way so this is how they look like in practice and this fragments code and in my opinion is terrible for readability so let's take a look at the following on the left we have something called a board that can only be called by the seller so we do this via modifiers here and then we do the same thing here I don't know about you but this is much more readable this one line solution than whatever this is and now consider that most modifiers are used like this they're they're imported from some random place and used like this yes the naming is kind of telling what it's supposed to do but it's still pretty it's not very transparent and most uses for modifiers are stuff like only seller or re-entered cigars where we can use and should use things like track effects interactions so all can be done in a single line of code like the like this so it's just fragments everything this is also going to be a spicy one so inline mule so yes using Google does save gas but there's a hidden cost it makes your code completely unreadable so this here is a snippet from openc it's used to transfer erc20 tokens uh so yeah I generally find you'll find for stuff like arithmetic but using it for large parts of the business logic shouldn't be done it makes it hard to audit read and yeah as Nikolai moshaken said complexity is the enemy of security and we should be avoiding complexity so user-defined operators they are a relatively new feature they were introduced in 0.10.19 and they're designed to make user-defined types easier to work with so in addition to having the same problems as modifiers you also have a problem of not knowing at a glance if the function if you are executing a function so we've seen from other languages how people get to carried away with stuff like this and uh yeah it's not something that should be happening in a smart contract programming language that should be readable and to properly overload an operator you must understand transitivity commutativity and distributivity and maybe you do know how all of this works but a lot of lots of people don't I certainly don't so um yeah but there are some cases where uh they do have legitimate use cases like custom decimal types where it's very hard to get multiplication subtraction and all these kinds of stuff hard to get wrong and the solidity team is aware of the complexity but in the blog post when uh 0.8.99 was released they argue that it reduces complexity and increases readability and this is the example they gave which is it was Cherry Picked but yeah sure let's go with that delegate calls so it creates a new sub context as if calling itself but with the Call of the cold contract and what this essentially means is that we have a proxy contract that delegate calls into a logic contract and what this allows us to do is to have proxies that have business logic here so it costs relatively to deploy a proxy contract is relatively cheap and then you can use the storage of this one with the logic of this one and that makes things like upgradable contracts diamonds if you're masochistic and obstruction account obstruction a bit kinda are possible due to it so the evm has storage source that are 22 bytes long so we have a unit 256 this is the Alias for that uh this is one slot we have an address this is antibytes and some balls which are packed into one slot and then we have two additional slots that are taken up by these things so it has a really bad reputation because it's very easy to blow yourself up if you use it incorrectly uh if you get stored results wrong between the proxy and logic contracts it's very easy to get undefined behavior and solidity High because of this solidity how is it as a low level call and there is no way to check if you are doing store results properly so at range shower we deal with a lot of proxies and we delegate call into large business logic contracts and this is something I would really like to see fixed or like improved on an added as it's very hard to keep track of all these things so C is the reference compiler for solidity and the lower level of workings of it aren't documented very well so if I do make some mistakes somewhere you have my Twitter please scream at me so uh yeah let's go it's very bad at optimizing code solidity code is consistently worse than inline Yule and this is really bad because we have modern compilers that almost always produce code that that are better than a human could ever write like if you take a look at GCC or Clank they will always produce better code because they have 20s or so years of research put into them they have all the knowledge of an instruction set you're developing for and the humans simply cannot do that and here we see that solidity is up to 50 worse than using it with fuel it's really bad even if you take hidden checks like checking if interest and to something that shouldn't be sent and things like that that's still not an excuse I there should be at least parity between the two a very good example of this is the free memory pointer so solidity needs a free memory pointer due to having Dynamic size types so this is how that looks like and evm opt codes and uh you can scan this to learn more about it so here we see bytes is a dynamic type we do not know its size and Advance it can be anything and it makes sense to have a free memory pointer here but if you take a look at this by Studio static we know the exact exactly how much memory we need in advance and the three memory pointer is still there so this is a really good example of how is unaware of what your code actually does via IR so it's designed to optimize your code and which basically means in the soci context of it to modify it so that its first most quickly and spectacularly so what do I mean by that it's a feature of the compiler that uses Yule an intermittent representation of it to optimize it hopefully and the plan is to replace it with Legacy byte call Generation by the end of the year and if you use the Via who has used via before okay so you know how slow it is yeah and in addition to being really slow it contains semantic changes compared to Legacy bicycle generation which means that the code you generate without yir can produce different outputs to code you generate with it this is completely unacceptable in a smart contract programming language yes there are technical reasons for why it's like this but at the very least I expect something like a pragma where we put solidity version but like a IR and it is largely undocumented most of my research for what via IR is and does came from Reading GitHub issues which is kind of funny this is a very notorious bug with yir that was fixed relatively recently where uh IR based compilation increased context size when an internal function is called many times so what that basically means is that if you call an internal function multiple times it will inline it and your code will have up to be up to like three times larger than it should be so yeah this is a really funny anecdote if you wanna read that you can scan the QR code so to conclude soluti has numerous design flaws and limitations that make it less than Pleasant to work with it's a mixture of high and low level features make it pretty awkward and comparison to use and the lack of compilative imagination suppose the programmers to write inline assembly to not have to deal with the compiler and I think that one hurts the most because if you have to use inline assembly you feel the designing of programming language and give Viper a go Viper wipers wiper is great it's not doesn't have imperative it's loyalty doesn't have Dynamic types it doesn't have infinite Loops but there is some traders that they make to have it be a compelling option so if there's one thing I want you all to take away from this is that maybe we need to rethink about how we are designing and writing smart contracts so thank you if you have any questions DM me on Twitter or ask me here or if you want the slides shoot me a DM here's my Twitter and uh yeah thank you [Applause]

Automatic transcript — names and jargon may be misspelled.