 Is that okay? Yes. Like that? Cool. Wonderful. Yeah. Thanks for coming on this day. Actually I expected perhaps two or three people to turn up here. The rest is at the lake or in a cocktail bar or whatever, things you usually should do on such days. So thanks for coming. Yeah. For this talk, in this talk I try to explain some new features of Solidity 050. This is special because we follow the Semver versioning scheme and this means 050 is a breaking change. And the last breaking change was I think in something around October 2016. So quite some things happened since then. I will mostly talk about the actual breaking chains and not the actual breaking changes and not the features that happened in the I think 25 releases we've had since then. So yeah, for 050 or for the breaking changes of 050 we mostly focused on safety. So we noticed that it's often better to force the user to be much more explicit about some things. We will see examples later. And we will also remove some things which can be interpreted in different ways. So we'd like to everyone be clear about the semantics of the language. And we will also add some more runtime checks. Adding runtime checks is always tricky because the more checks you do, the more expensive the operations will be. And you kind of fight with users who want their smart contracts to be cheap and then you fight with other users who want their smart contracts to be safe and you always have to find a middle ground there. Okay let's go through some of the changes. We start with visibility constructors and events. So these are things which you might have noticed already in the recent non-breaking versions because we so most of the changes we gradually introduced by the way of adding warnings if you still use the old non-recommended way. So this is a simple smart contract in the 040 syntax and if you know the language a little then you notice at least one bug. And the bug is that this initialized function is meant to initialize the smart contract so it should only be called from the constructor only from a privileged user and the reason is it sets the owner but since there is no visibility specifier here it's publicly visible can be called by anyone so anyone can change the owner of this contract. And yeah most of you perhaps know that this is something that actually happened and because of that we now require visibility to be specified explicitly and yeah in current versions the compiler produces a warning from 050 on it will be an error. So now this bug is fixed and the other something that also happened is that the constructor is defined by using by defining a function with the same name as the contract and now of course over the course of development you might change your mind about the name of the contract and you change the name of the contract but you forget to change the name of the constructor. Because of that we now force the constructor to be specified in this new syntax where you don't use the function keyword but a special constructor keyword and now you can change the name of the smart contract without having to change the name of the constructor. And then events so here we here we call an event. It looks very similar to a function call but events are rather different they don't actually execute any code they just log information and because of that to make it explicit we require an emit keyword to be used together with events so that's not a big security thing but it's just nice to have I think. Good then the next thing is to force more yeah force users to more explicitly mention the types they want to use and yeah here this is also something that actually happened the var keyword can be used to declare a variable when you do not want to specify the type explicitly and the compiler tries to deduce the type and it does that from the first assignment that is done to the variable and here in this case the variable is designed from zero and now what is the type of the zero literal constant so literal constants always have the smallest possible type where the constants constant fits inside and because of that this is an unsigned editor with eight bits and now of course the problem is when you pass an array which has more than 255 56 whatever elements then this loop will not terminate because I is always smaller than length because the largest value it can hold is 255 and you do not have overflow checks here so even if we had overflow checks this is not the behavior you would want because you would not be able to pass in an array with more than 256 elements okay long introduction no the easy thing here is just disallow bar so we had a warning for exactly this case because that happened a lot so we have a for loop and do not declare the type here we already had a warning for a long time but now we said yeah I mean just force users to specify types explicitly that that is also a rule we follow or we more or less follow inside the compiler itself so I think that's that's good to have some people complain that in some cases this results in quite verbose code but we're trying to introduce aliases or yeah type type definitions that might help in these cases then another thing which is perhaps not too visible here but in other cases a is a reference type a is an array a reference type which so a itself points somewhere and it can point either to memory or to storage or to call data and in many situations I always yeah fall into this trap from time to time in many situations you make the wrong assumptions about where it actually points and because of that we force the memory keyword to be used always when you declare or when you use a type for yeah not not yeah we need a clear variable yeah so then the next thing storage pointers so this is also this is something that is also a bit improved with having to specify the data locations so the local variable p here is of this struck type and by default it points to storage now since we force a data location specifier here this doesn't happen too often because people then think oh yeah it's memory so you put memory here and yeah perhaps I should not go too much into detail here so storage is statically allocated so it's impossible to create new storage variables storage objects in a certain way and this leads to this variable actually having an invalid value so it has to be initialized with something but there's actually no nothing the compiler could initialize it with to be valid and because of that we now force the user to always assign p assign something to p when it is declared okay and because of that it's better to completely rewrite this thing so you see peace peace defined here and it has to be directly assigned from somewhere yeah and this way it's much safer because there's no way for a storage pointer to be invalid unless yeah there's there's some cases you might find out but it's much more much harder to get it to such a point good that storage pointers now something that was also requested quite often is changing a change in the scoping rules some of you probably don't even know but solidity inherited its scoping rules from JavaScript and JavaScript scoping rules are really really weird the thing is JavaScript scopes are always functions so usually so when you declare a variable here in most languages it can only be used inside this block which is still limited by curly braces but in JavaScript a variable that is declared somewhere is always visible in the whole function and more over it is also visible before it was even declared and even visible outside of whatever so this is valid solidity code and a version of it will also be valid on JavaScript and it returns three yeah with 0 5 0 this is not possible anymore and we have regular block scope variables as you would expect from something like C++ or Java so even this code is valid that this is not this cannot be done in 0 4 0 because you would declare a variable here whose scope is the full function you declare a variable with the same name here which has the same scope so you have a clash of variables it doesn't work but this is of course very idiomatic code to write a for loop so yeah and with the new roles this code compiles and works correctly so okay block scope means as I said variables are visible inside of the curly braces block they were declared in with the single exception that if you have a for loop and declare the variable in this first initializer block it is visible in the for loop but not after it and another advantage of block scope variables especially in solidity is that it helps a little improving this at most 16 variables per function limitation because variables can be removed from the stack when their scope ends previously the scope was the full function so you could really remove it and now you can remove functions when their scope ends so you can actually have more than 16 variables in a single function as long as you don't have 16 variables more than 16 variables visible at the same time okay so if we already have 15 functions in this 15 variables in this functions declaring this I variable twice doesn't hurt because they are unrelated good we're almost done we also have some functionality improvements there is now way to remove the last element of a storage array very efficiently and idiomatically then we expose the ABI encoding functions so there's ABI dot encode which does regular ABI encoding and returns a byte array ABI dot encode packed which does packed encoding that's the encoding that is used by the hash functions for example and there is also encode with selector and encode with signature those can be used to create so ABI dot encode just creates the byte array that follows the four byte function selector am I talking crap here or are you following so this is really really deeply technical so I'm really sorry about people who are already asleep so ABI dot encode just result returns the actual ABI encoded payload data and if you want to use that with the raw function call you have to prefix that with four bytes that tell which function to actually execute and because it would be so prefixing data onto byte arrays is kind of weird so we have two additional functions that can do that in one run so the first argument is this four byte function selector and then the actual data arguments follow we'll also support enums and structs and interfaces that will request it quite often because that actually allows you to define yeah interfaces for smart contracts or for classes smart contracts in a useful way then so this these were the three functionality changes we have tons more most of them were introduced already earlier so you might already know about that then some minor safety changes so call the call function so address dot call has always been a very weird thing with weird behavior most people didn't know about and that's why we decided to simplify it it now only takes a single bytes parameter so just raw bytes and these are forwarded and that's it previously and so if the first argument would was a bytes for had bytes for type then it would encode differently and also the encoding of call was very weird it was neither ABI encoding nor packed ABI encoding but something else and whatever so now you can use call and you would use these ABI encoding functions to create the data for call and then just yeah this of course applies to delegate call and all the others also the hash functions only take a single bytes parameter if you want to get the old behavior you use shot three of ABI dot encode packed off and then the actual data while cut tuple assignments are removed this is when a function returns multiple values but you are only interested in the first you could do a comma equals function call and because that was easy to get wrong now the left-hand side has to have the same number of components as the right-hand side so you would do a comma comma comma equals interface functions have to be external that's the only reasonable way for interface functions because you yeah and then next thing is also interesting so the bytes types are you have byte arrays of up to 32 bytes and they are very similar to the unsigned integer types which also come in various flavors up to 32 bytes the main difference is that byte arrays are left aligned in the world and integers are right aligned in the world now if you convert between byte arrays and integers of the same size what would you expect to happen how does it convert so convert the number eight which is a unit eight to a bytes one so a byte array of length one what happens can you see it again how many zeros in the beginning and hex or in binary yeah right so it it takes the single byte which was right aligned and just shifts it to the left exactly so I hope this is what everyone would expect and it gets tricky if you convert between these two when the number of bytes are different because so okay if you invert if you convert between you and eight and you in 16 then you would expect nothing to happen it's just the the the range is increased and if you convert between bytes one and bytes two it would just add a zero byte now the question is what happens when you convert between you and eight and bytes two does it first does it does it go through you in 16 or does it go through you in 8 so does it first where does it add the zero on the left or on the right right so that's the tricky part and that's why we disallow that and you still of course can get exactly the same behavior by just having two conversions but you explicitly specify in which order you convert and so it should be visible what happens right shift on signed integers this is actually my mistake I thought oh yeah shifts are just divisions by powers of two or multiplications by powers of two which is of course incorrect for signed integers and with zero five series fix it this will yeah so this is only right shifts on signed integers which probably nobody actually uses since it's not just a division by a power of two it's a little bit more expensive because the EVM does not have native shift operations but I think that's fine if nobody uses it anyway yeah and then yeah constant state variables were very weird because they were kind of use usable as macros so you so state variables are these variables which are declared at contract level and if they are constant they don't have to be constant in 0 4 0 but instead you would assign them from an expression and then this expression is copied everywhere where this variable is used and if it's not constant then it results in a different value and which of course defies the purpose of a constant and now we're forced it to be pure which means compile time constant and thus it is still so the the way the code is generated is still the same the expression is copied everywhere but at least the value would be always the same good then the major safety changes view and so since by centium we have the static call upcode which forces so which enforces at the level of the EVM that you cannot change the state of the blockchain and view and pure functions are disallowed to make any modifications to the state view can read from the state but pure functions cannot even read from the state and we cannot enforce so at the level of the EVM we cannot enforce the difference between view and view and pure but we can enforce the difference between regular functions and view or pure functions and that is why we use static call it might happen that you compile code solidity code and then run it on a virtual machine which does not implement static call so on so sometimes test nets if you run a client in test net mode then sometimes it uses the very old frontier release and in that case you have to manually set your EVM to the right version so to by centium to do that if you if it's impossible to set it up by centium then you can specify so in a compiler setting you can say this is the target EVM version I want to compile for and then it would not use static call and then so this is also something that happened some I think it was an exchange implemented the ABI encoder incorrectly and this would so this is again this bytes alignment thing so what happened was that if you so you specify an address to send your money to and if the address has leading zeros then this encoding library would just shift it to the left so it would instead it would not right align it but it would left align it and that yeah that of course results in the money ending up in the wrong on the wrong wrong address but the good thing is that the way they was implemented was that it actually did not write padded with zeros but the data was just one byte short and yeah I'm really going into details there but eyes are still open that's good so when you read from call data then everything is zero padded so the data that is passed on to a smart contracts actually ends in an infinite number of zeros and because that it still worked so if you if you call a smart contract and give it not enough data then it still works because it just fills with zeros but this is yeah most in yeah 99% of all cases not desired I would say and because of that we now check whether the data that is supplied to the smart contract is long enough to hold actually the yeah to be decoded to be decodable yeah so this might cause some calls to fail if you do low-level stuff proxy contracts or something like that so yeah please take care there and then inline assembly in the very beginning it was a very yeah you were able to do a lot of things almost all things that is possible with bytecode and due to several reason we want to restrict that one reason is because you want to compile to web assembly and not only to evm and for that we disallow basically everything that messes with the stack or messes with the program counter this means explicit jumps are disallowed you have to use the control control flow statements we offer so switch if for yeah and also direct access to the stack is disallowed and this actually turns inline assembly into a language that does not really assume that there is a stack or that is yeah they're just variables and you can call functions and assign to variables that's it good yeah and then there's another yeah weird thing which is different in other languages which perhaps I'm also to blame because I didn't find it in the review so do why so the do why loop is basically a similar to a while loop so you the control for enters here and then runs this and the difference to the while loop is that the condition is checked at the end and if the condition is true it jumps back to the beginning runs it again and checks the condition again and if the condition is false then it exits the loop here now there are these statements called continue and break continue just skips the rest of the loop and continues with the next iteration and break exits the whole loop exits loop completely and yeah somehow in Solidity continue was implemented in a way that if you have continue here it jumps to the beginning of the loop and skips checking the condition because I mean the conditions is daddy and then at the end so yeah yeah that's of course not very useful and not the way do while is implemented in other languages so now continue does not jump to the beginning of the loop but to the beginning of the check okay that's about it do you still have questions yeah I didn't mention that because it's not finished for 050 actually so are you talking about this new a bi decoder yeah that's still experimental and the reason it's still experimental is because we wrote it in a way which is extremely modular so every tiny little function yeah every tiny little thing that is to be done inside this decoder and encoder has its own function and most of the time these functions only consist of a single opcode or sometimes they even do nothing they just return the input and the idea was that it's much easier to implement it in a correct way because you implement every single thing only just once and then call it from everywhere but it will of course result in very inefficient code because you have tons of function calls and jumps and because of that we implemented an optimizer a new optimizer just for you just for inline assembly and we're not yet confident in that optimizer that's the reason so if you use a bi encoder v2 now it is that the optimizer is switched off so you can use it but it will be much more expensive probably so it's basically the same as a bi dot encode okay so that there's encode with signature and encode with selector the difference is that one of them I think it's selector one of them takes a bytes for which is just the hash the beginning of the hash of the function signature and the other one takes a signature itself and then hashes it yes so for the one you would pass f opening parentheses closing parentheses in a string and the other would get four hex bytes so we did not change anything in the storage layout yeah hopefully not so I mean not not because of the storage layout so storage layout is something that is very critical and if we change it at some point there will be big big warning signs and perhaps even a runtime check or something like that so so and the reason it is critical is because through libraries can access storage of other contracts and of course you can you can link against a library that was compiled with a different compiler version because that we actually cannot ever change storage yeah memory layer is different so memory layout is changed all the time actually we did change so there's this so at the position 0x40 there is a special value that points to the first uh free space in memory so if you want to write something into memory without overwriting something then you would write it there and then increment the or increase this this pointer and what we changed was not the location of this pointer but its initial value so and this was done in an unbreaking change because I hope it didn't break anything so yes yes yeah sure I mean we're aware that assembly or there are libraries that use in that assembly and that's also how it should be of course and if we ever change that then there will also be big warning signs so memory layout itself was not changed it was just this change where the free memory starts so we changed it from so its initial value was 0x60 so right after the pointer itself and now it points to 0x80 um and the reason is there is in this gap it's a single is it a single 32 byte gap and we assume this gap to be always 0 and we use this assumption to have more efficient uh initial values for dynamic memory arrays previously if you so if you if you declare a variable of memory type with a dynamic array it would create a new memory array of length 0 which occupies 32 bytes in memory for this length prefix and the length prefix is 0 so uh what we now do is we just initialize it with a pointer pointing to this gap and because we know or we hope that the value in this gap will always be 0 all memory arrays actually point at the same value and it's 0 so the length of the array is 0 so there's no data that has to follow using assembly for example was building stack slots there is that scratch space and scratch space and that's the first 64 bytes okay so this is always can always be used uh unless you're inside of the expression somewhere and of course you can use you can also use the the point where the free memory pointer points as scratch space because you don't have to increment it if you don't want this data to live on exactly yes we have uh yeah I think all of what I just said is documented perhaps not the part that uh you can expect the free memory pointer to point to 0 filled memory so it's internals of the compiler somewhere in the in the Solidity documentation I think it's at the very end of the in-depth part okay more questions yeah um so I can see it again um yeah there's a plan to make it return two values a Boolean success value and a memory byte array with the return data and the reason we didn't include it now was because it's not really useful because you cannot we don't have ABI decoding functions and so since we don't have ABI decoding functions you have to resort to inline assembly anyway and then you can just do the call with inline assembly to begin with and the reason we don't have ABI decoding functions is mainly because we don't have a nice syntax so the difference between ABI decoding and encoding functions is that the so in both of them you need to specify the types somehow you want to decode and but for in code just you just take the types of the arguments you put into that and for decode you kind of that doesn't really work so you can look at the types you want to pull out but that yeah so um and the syntax of solidity uh doesn't really allow for a way to specify the types in a nice way so we thought about using I don't know perhaps um how do you call it angle brackets yeah but the parser doesn't really support that yet so it yeah will be in 060 at the earliest more questions so um one of them is the call data size check another one is um add mod and mall mod these are these these are built in functions that take three parameters and do modular addition and multiplication and they check for the third parameter to be zero this is probably not something you would encounter but yeah and is there another one so something we already added and was perhaps not such a good idea to add it already now was check the size of the return data when you call a function that costs some some some tokens that claim to be ERC 20 tokens to break that's another runtime check we're currently also experimenting on overflow checks uh but what I said in the beginning so if overflow checks are nice to have but they will be more expensive so we're currently evaluating how expensive they will be and uh regardless uh there will be a keyword to mark an area to be unchecked so I think that's also something let's see sharp as uh yeah well these overflow checks would be switched off can we assume that like uh I didn't get that moving into what anymore I mean it didn't really have type deduction anyway it just took the type of the value I'm not sure if you could call a type deduction so so the explicit type conversions are something you shouldn't need to do anyway unless you do some lower a little bit fiddling so yeah we try to kind of make that a bit more visible that these explicit type conversions um so when people try to do that but yeah haven't decided to do anything about it yet um if you have some examples to share then please contact me so but yeah implicit type conversions are always possible when the value range grows or is the same and you don't need to do a conversion they just assign it to the value and it implicitly converts so if you okay if you change yeah so if you for example uh as we had earlier you in eight to bytes one that has to be an explicit conversion even though that that value range doesn't really increase so you won't notice the difference okay but that's this allowed anyway now so or you won't notice the difference between converting from you in six you in eight to bytes one and converting from you in 16 to you in eight for example so this this the the second actually truncates data and the first does not truncate data it just changes the alignment so having a more fine-grained distinction between those could be something we should add but again it's unclear how to do that in a syntax which syntax to use for this distinction yeah yeah i hope that uh the switch to the new intermediate language you will be something i can focus on soon and the optimizer that comes with it i'm not sure how to get that faster so and this is also something the user won't really notice so it was hard to to justify working on that but in the end we have to do it because i think we have to move to something like web assembly or also yeah get kind of safer code generation because it's much harder to make mistakes in this intermediate language and also the optimizer might do much more things that weren't possible before and then of course the the smt component so the the static static smt based analyzer formal verification component we're pretty far there already so it now accepts storage so it can handle storage variables it even handles branches and recombines the control for branches later on uh the main thing we will have to add there next is handling modifiers and when we're at that stage i think we can have a proof of concept release of that component yeah that's something i want to avoid because you can't rely on smt checker or i don't want to rely on them so there's some things that the optimizer can do but we have to be really careful i mean the the smt checker is just a black box anything can happen inside there uh anything can change between version version changes and so on so yeah huh no it's just something like yeah someone else is doing it and they you don't know how stable it is i mean usually they don't have bugs they only have boxing components which were recently added but uh okay then thanks a lot for coming and please do you want to say something about the next meetup or