start	end	text
1050	4870	Great. Yeah, hello, everyone. My name is Sebastian.
5770	13450	This work is about identifying and fixing out-of-gas errors in smart contracts with
13450	21890	what we call smart fuzzing. And it's joint work together with the group of Professor Vijay Ganesh
21890	28410	from the University of Waterloo, with three great PhD and Master's students.
29370	36210	So just starting with a quick intro, but you all probably know this. On Ethereum,
36210	42830	you have smart contracts that are executed on the EVM. And calling a function on one of those
42830	49590	smart contracts changes the state. And these state changes often involve transfers of funds.
50130	57170	However, these smart contracts are just programs which may contain bugs. And exploiting those
57170	67510	can lead to stolen or frozen funds. So there's another part of the intro here is that
68530	75750	Ethereum virtual machine has this gas mechanism, which charges callers when they want to execute
75750	84230	some smart contract function. And the execution fee is computed by the product of the gas price
84230	90970	and the amount of gas that that code consumes. Now, in order to prevent denial-of-service attacks,
90970	97830	there's a block gas limit. And if the gas consumed by a certain smart contract function
97830	106520	exceeds this block gas limit, then the transaction is reverted. However, the gas is wasted.
107070	114050	So the caller needs to pay that price. And like I mentioned, it's meant to prevent denial-of-service
114050	124530	attacks on the Ethereum network because people don't want to... if a malicious attacker submits a
127770	136150	very resource-intensive piece of code, it could lead to a halt of the network. However, this
136150	139970	defense mechanism, which is the block gas limit, may also cause a denial-of-service
140820	149110	on smart contract functions. And this will lead to frozen funds, where by frozen funds,
149110	158630	you can also see them as lost funds. Here's a toy example. For instance, you have a
158630	165930	naive implementation of a bank in a smart contract. And in that implementation, you have this function,
165930	173690	which is called push interest payments, basically pushing the interest that the customers of that
173690	183630	bank received. And it iterates with this for loop over all users. It does some heavy computation,
183630	189610	which is not shown here, in order to compute the interest for each user. And then it sends
190570	199070	each user the amount of interest they are due. Now, you notice here that this loop bound is
199070	206390	controlled by users, because the more users are registered, the longer this loop is going to be.
206590	213750	And if it gets long enough, then the block gas limit will be reached when executing this function,
213750	218130	which will lead to a denial-of-service and no one will get their interest anymore.
219710	227110	This, a similar sort of situation where the block gas limit was hit happened a few years ago
227850	237270	with a governmental smart contract where they were set to pay out a jackpot of 1100 ETH.
237530	243910	However, it got stuck because the function that was meant to pay out was using too much gas.
243910	254270	And this was due to the fact that the contract wanted to clear its internal storage. And doing
254270	264430	that using these two instructions, which compiled to code which iterates over all locations and
264430	271290	deletes them one by one. So basically, due to the fact that there were too many participants
271290	276790	in this smart contract, it was hitting the block gas limit and the funds were frozen
277290	285930	for a certain period of time. However, with a new hard fork, the block gas limit was increased.
286010	293190	And the winning user was able to get their jackpot out,
293830	300550	thankfully. But it took some time, they couldn't do it immediately. And if there
300550	305710	were no hard fork, or if there were more participants, maybe it was still be stuck.
306510	314290	Here's just an indication of how the block gas limit has evolved over time.
314290	318070	So you can see at the beginning, it was somewhere around 3 million.
318070	329750	It was increased up almost to 5 million in 2016. However, it also was decreased at some point
329750	339330	for a shorter period of time. And then afterwards, it keeps increasing. At today, it's around 10
339330	347410	million. And it may also increase further, but who knows. So this is a dynamic parameter.
347410	355130	It's not exactly changing every day. But people should keep in mind that this is not something
355770	363550	that you can rely on forever. And what we see during our smart contract security audits is that
363550	370590	many projects still contain these gas usage issues. There's, of course, state of the art
370590	377050	tools like Slither and Mithril, which can detect these kinds of concerns very easily
377930	386810	using static analysis, for instance. And they are freely available and well known in the community.
386990	391150	However, the question is always, what do you do after you detect them? You tell the
393050	398770	developer, yeah, you need to fix it. And then he is like, how can I fix it? Of course,
398770	406130	an ideal way to fix this would be to completely remove the loops. But sometimes that's not an
406130	410670	option. And when it's not an option, what you can do is to do some kind of gas analysis
411270	421410	to determine how much gas the instructions use. And if possible, add a require statement
422070	429810	at the beginning of the function somewhere to notify the user that this is going to fail
429810	441010	with an out-of-gas error and not make them waste too many funds on the actual gas
441010	449890	until it hits the out-of-gas error. So this currently is sometimes manual work to detect
449890	458230	this bound or what parameters could lead to an out-of-gas error. And it's pretty
458230	464670	tedious depending on it's very specific to the smart contract that you're using.
465690	472030	So in this talk, we basically want to automate this process. We want to generate
472030	478110	this kind of denial-of-service exploit and then also fix the issue.
479730	486130	And there are several challenges. The first one, which is probably the easiest of them all,
486130	493270	is how do you determine the exact gas usage during execution? Then depending on which
493270	499630	functions you may have, they may have like a large search space. So if you have several
499630	507990	function input parameters, which are uints or strings, they can have a lot of possible
508630	513330	values. So how do you search through all of those possible values and determine the ones
513330	523430	which could lead to an out-of-gas issue? And the third one is also the fact that you're not just
523430	530010	looking... you cannot just isolate this search for one particular function because several
530010	538070	functions might be dependent on each other in the sense of the state variables that they
538070	544690	change. So we're going to see some examples of those. For determining the gas usage,
544690	552130	there's multiple approaches. One can be done pre-execution using the estimate gas function
552130	559330	from Web3, or you can do it post-execution using the gasLeft function from Solidity.
559850	563370	And we use the gasLeft function in our implementation.
564690	570470	The second challenge was about large number of inputs, and there's different fuzzing heuristics
570470	577590	you can use in order to do that. The brute force one is just randomly picking possible
578250	583330	input values, which is slow. Another one, which is faster but is not always applicable if you
583330	588330	don't have a strict ordering between your inputs, is to use divide and conquer.
589690	595370	And the one which we'll be using in our approach is reinforcement learning, which is
596030	605110	also fast and more generally applicable than divide and conquer. There's also other possible
605110	610430	heuristics, so we're not saying that these are the only three. Of course, many people will come
610430	617810	up with other heuristics, which are maybe better, maybe not. But what we wanted to look into was
617810	623890	how to use reinforcement learning for this kind of purpose. And in our approach, we model the
623890	634690	problem as a Markov decision process, where the S is all states of the EVM. A, the set of
634690	645170	actions is basically smart contract functions with possibly random inputs or maybe more
645730	654610	carefully designed inputs. This is basically the secret sauce or the most important part of
655630	660990	the modeling part. How do you generate your action set? Which actions your reinforcement
660990	667950	learning agent can perform? The probability of transitioning from one state in the set S to
667950	674610	another, we set to one because the EVM is fully deterministic, so there's no question whether
675390	683150	executing a certain function with certain inputs in a state will lead to different states. It's
683150	690950	deterministic. And then the reward function for a certain state is basically one minus
691550	699750	the amount of gas you have left over the block gas limit. And again, with the reward function,
699750	704190	we're playing a bit around with it at the moment. This is just to give you an indication.
705140	714710	We actually are also penalizing if we want to get to the exact bound where this
715300	724350	out of gas error happens. So we're looking at ways in which we can penalize if not only that
724350	731830	there's no gas left, but it actually would use much more gas than available. So for that,
731830	740650	we're setting the block gas limit pretty high. One example of a super simple function where
740650	747190	such an out of gas error could occur is shown here with this sum function. It's a pure function
747190	756830	which just iterates over integer numbers up to a given value n and computes their sum.
756830	761310	So the goal of the reinforcement learning agent here would be to
762110	768630	find a large value for this input n such that this function runs out of gas.
769290	778070	The second example is a bit different. It has two input parameters and it computes a division of n
778070	785830	by m in order to obtain the bound and then iterates and computes the sum. And now you can
785830	791610	see that the goal of the reinforcement learning agent has slightly changed into finding a large
791610	799650	value for n and a small value for n. But m should not be equal to zero, otherwise we have a division
799650	807150	by zero. And the third example, which is showing the inter-function dependency, is actually
808770	814970	a contract containing several functions and a list of entries as a state variable.
814970	820390	And you'll notice that the function which contains the loop is called sumEntries.
820810	828490	It iterates over all these entries and computes their sum. However, this function does not have
828490	834750	an input parameter as the ones we saw on the previous slides. This basically means that
835770	843730	another function in the smart contract is probably going to affect the length of this list.
844190	851030	And the one that it does affect is this addEntry function.
851170	858210	And other functions like getEntry do not affect this length. So the goal here is the goal for the
858210	863870	reinforcement learning agent, which doesn't understand the semantics of the names here.
863870	869670	So reinforcement learning agent doesn't understand what addEntry means or getEntry or sumEntries.
869670	876270	It just sees functions and tries to execute them. The goal here is basically to generate a trace
876790	885370	of function calls of this form, and then to determine the value of n,
885370	892370	such that when it calls the sumEntries function afterwards, it's going to run out of gas.
892930	899890	And the question here is, how do you determine which functions... let's say you have a smart
899890	907630	contract with, I don't know, dozens of functions, right? There are such smart contracts. Which one
907630	916350	should the reinforcement learning agent call in order to obtain a proper trace where an out-of-gas
917060	923210	issue occurs, right? This may be very difficult. It's a very large search space because you also
923210	930650	have possible different function calls with many parameters. So it's a large search.
931170	937030	The solution that we propose for this is to first do reverse taint analysis and then
937030	943790	forward taint analysis on the smart contract in order to determine which functions are relevant
943790	950050	to call for the reinforcement learning agent. If you're unfamiliar with taint analysis,
950050	956950	it's a form of information flow analysis where you taint or tag a memory location,
956950	962570	which could be a variable x, and then you trace the flow of the execution of the smart contract
964330	971170	and the tainted memory location. And this way you determine which other locations or instructions
971170	979970	are affected by this tainted location. This taint could be either explicit,
979970	986130	where you have a direct assignment between the tainted memory location and another,
987130	992530	or it could be implicit, where you have a condition that depends on this tainted memory
993490	1003870	location. So here's the example, slightly modified function, some entries from our
1003870	1009930	third example on the previous slides. We have here a list of entries, we have this function,
1009930	1018050	some entries where we also introduced a parameter n just for the sake of illustrating implicit
1019630	1028190	information flow as well. And basically, it compares whether this input parameter is zero,
1028190	1035110	or if it's greater than the length. And based on that comparison, it assigns the bound to a
1035110	1041730	different value, right? And then it loops over that bound. Now here, we start our reverse taint
1041730	1054330	analysis from the last executed instruction that meaning here, it's basically the loop bound,
1054330	1061270	and we go backward from there. And we basically taint all the other memory locations that are
1061270	1067650	affected by the bound. So n is affected by the bound explicitly because it's assigned here.
1068180	1075790	And it's also affecting the entries length. However, it's also implicitly affecting these
1075790	1084490	two values here. It's also therefore implicitly or explicitly affecting the state variable
1085010	1090440	entries, right? And now that we have this information with the reverse taint analysis,
1090440	1097960	we do our forward taint analysis where we know that our entries state variable is tainted.
1098400	1105160	And we start looking into the functions. And we see that the addEntry function
1105900	1113400	is also tainted because it affects the entries length. The other function, which is called
1113400	1120420	getEntries, does not affect the entries.length. Therefore, it's not tainted. And we can do
1120420	1125660	that with more other functions that are in the smart contract. This way, we have a subset of
1125660	1132100	functions that our reinforcement learning agent can call. Now, the question is, what do you do
1132100	1141340	once you know where and when the out-of-gas error occurs? Basically, fix it. And one way to fix it
1141340	1145220	would be to add these kind of require statements. And we
1146100	1152260	revisit the previous examples that we saw on the previous slides.
1153360	1159520	The first one was this simple sum function. And here, you can basically add a require statement
1159520	1166820	at the beginning with this bound that you determined before. This, of course, can be
1166820	1173380	something that you can set depending on how the block gas limit evolves. So, it doesn't
1173380	1178400	need to be a hard-coded constant here. It could also be a state variable of the smart contract.
1180080	1186380	This way, you prevent the caller from wasting gas if the value of n is too large.
1187740	1193040	Similarly, you can do a bound on the second example that we had.
1194000	1200880	And you can place the require here. Later, you can place it earlier.
1201860	1209020	And you can also do it where you have multiple functions. And notice here that we're not
1209020	1215000	blocking the sum entries function, which actually contains the loop, and it would actually be the
1215000	1222520	function that reaches the block gas limit. You place the fix inside of the functions which affect
1223040	1232860	the entries.length and would basically prevent the length from becoming large enough
1233840	1236500	to cause an out-of-gas error.
1238780	1244960	So, that was pretty much it. In conclusion, we all know loops can cause
1245720	1251560	out-of-gas errors, and these errors can lead to frozen or lost funds.
1251560	1258660	And detecting such errors is easy, but determining the exact input that is going to
1258660	1267320	cause it is harder. And here, I'm not just saying any input, but basically being able to fix.
1267320	1273620	So, we're talking about the boundary condition between where it doesn't run out of gas and then
1273620	1285660	it runs out of gas. So, in order to determine this input and to generate the fix, we use fuzzing
1286420	1292620	with reinforcement learning as a heuristic, which is fast and generally applicable.
1293180	1300780	And we also employ taint analysis in order to guide the fuzzing, so to guide the reinforcement
1300780	1305600	learning agent as to which functions should be called and which not.
1307640	1382950	That's my talk. Thanks a lot for your attention. Any questions? Yeah, me neither.
1393030	1396230	Yep. Thank you.
1404450	1422650	How's it going? Can you hear me? Hey, how's it going, everybody?
1424270	1435690	I'm just going to get my screen shared here. Yeah, I can also just hang out and...
