(Part 8) Ethereum Solidity - Assembly, Reducing Costs And Creation Your Low Level Expression(PT 8)

in #utopian-io6 years ago

Repository

https://github.com/igormuba/EthereumSolidityClasses/tree/master/class8

What Will I Learn?

  • Intro to assembly with a for loop
  • Low-level programming and transaction costs
  • Building not native decision taking expressions

Requirements

  • Internet connection
  • Code editor
  • Browser

Difficulty

  • Intermediate

Tutorial Contents

Generally speaking, it is not recommended to write assembly code on your Ethereum contract, but doing so has the advantage that you can significantly cut down transaction costs.
For most cases the savings won't pay for the extra work of coding assembly (depends on your familiarity with it though), but for some rare cases where your logic is too complex or you know exactly where and how to cut corners, go for it and save yourself and your users some wei (name of the minimum fraction of Ethereum)

I have already talked about Assembly in solidity on the third class of this series, but I have just mentioned at the beginning of the class and taught how to get away without using assembly (hehe)
https://steemit.com/utopian-io/@igormuba/part-3-ethereum-solidity-development-contract-mutability-delegatecall-and-calling-functions-by-address-pt-3

In this class let us dip our feet a little bit in assembly, also by the end you will know about one keyword/functionality that is available in every major programming language, but not on solidity, but we can implement it in just a few lines using simple assembly!

For loop converted to assembly

For loops are used to do certain tasks for a defined amount of times.
A typical for loop on Solidity would look like:
'''

for (int count=0; count<10;count++){
//some code goes here
}

That would make the code inside it be executed 10 times.
You can achieve the same result in assembly by doing the following using assembly syntax, instead of high-level Solidity:

assembly {//tells you will start coding in assembly
            for {let counter:= 0} lt(counter, 10) {counter := add(counter,1)}{ //more on this later
                _x := add(_x,1) //adds one for each round of the loop
            }

Both of the above have the same functionality, but doing that on assembly will be much more cheap in terms of gas costs, more on that later. Gas cost is measured in "wei", if you don't know what wei is, I explain briefly on this tutorial
https://steemit.com/utopian-io/@igormuba/part-7-ethereum-solidity-fallback-ethereum-fractions-and-collateral-backed-contract-pt-7
Let me explain the details and keywords from the assembly code (the latter one)

assembly indicates that we will start coding using the assembly syntax, a lower level programming language that talks more directly to the computer
let creates a new integer variable, note that everything in assembly is an integer, so saying "an integer variable in assembly" is redundant,l but I had to say it to explain it
:= assigns an integer to a variable
lt(x, y) checks if the x is less than y, if it is it returns the number 1, which means true
add(x,y) sums x and y and returns the result

Putting the assembly in a function

Just like Solidity does not allow you to write for loops floating around outside functions (I hope that you have noticed by now that everything, except variables, must be inside a function), you can't put assembly code anywhere because it does not make sense, it would never be called, and the compiler also won't allow you to do that, so I have wrapped the assembly code inside a function and changed one small thing

    function assemblyLoop() public pure returns (uint _x){
        assembly {
            for {let counter:= 0} lt(counter, 10) {counter := add(counter,1)}{
                _x := add(_x,1)
            }
        }
    }

By declaring on the function that it returns (uint _x) I can, inside the assembly code, manipulate the uint.
You can't manipulate other variables inside the assembly code, it has either to be uint or, if it is not, you have to convert it to bytecode and then work with the bytecode

If you are interested in that, here is a good work about returning strings
https://medium.com/@fratellopartigiano/returning-string-in-solidity-assembly-ea70e4bef829

Now, on Remix, I will create another loop, I will just copy what I have done before and adapted it to the new code, So both functions will work pretty similarly, but this new one will be using a "regular" for loop, just so we can compare the results

pragma solidity ^0.5.0;

contract solidityAssembly{
    
    function assemblyLoop() public pure returns (uint _x){
        assembly {
            for {let counter:= 0} lt(counter, 10) {counter := add(counter,1)}{
                _x := add(_x,1)
            }
        }
    }
    
    function solidityLoop() public pure returns (uint _x){
        for (int count=0; count<10;count++){
            _x++;
        }
    }
}

Now, chech the execution cost from thethe solidityLoop result
image.png

Compared to the same field of the assemblyLoop result
image.png

If you look at the execution cost it is clear who is the winner
BY USING ASSEMBLY WE SAVED ALMOST 20% OF GAS

NOTE: Transaction cost has little information about the real execution cost of the code as it includes more details from the transaction itself, whenever you are checking costs and the efficiency of your code, pay attention to the execution cost instead

Switch case

Before you proceed with this tutorial, I want you to try for your self to create a function that uses a switch case control structure, almost every other language has it.

Tried? I will give the answer now if you don't want spoilers...

So, turns out there is no switch case at all on the Solidity language, go ahead and search for it on the documentation
https://solidity.readthedocs.io/en/v0.5.0/control-structures.html

But that is ok, because now you have been introduced to the power of assembly, with it you can create your own functionalities and improve the language.

Now for the switch case

    function switchCase(uint _x) public pure returns (uint _y){
        assembly{
            switch _x //grabs the variable _x
            case 1{ //compares, if it is 1
                _y:=2 //returns 2
            }
            case 2{ // if it is 2
                _y:=1 //returns 1
            }
            default{ //if none
                _y:=0 //returns 0
            }
        }
    }

Yes, it is indeed a funny thing, they do not have a higher level switch case but have a lower level one.

Differently from the first example, this time I do not have a higher level switch case to show you, but the code works exactly the same as using other keywords, like this

function ifElseSwitchCase(uint _x) public pure returns (uint _y){
if (_x==1){
    _y==2;
}
else if (_x==2){
_y == 1
}
else{
_y==0;
}
}

Now things are more clear and assembly is not as mysterious like when I first mentioned on one of the previous classes.

Solidity is an ever-evolving language

I hope I didn't scare you, because personally I always get scared when it is time to touch on assembly, but it is not that difficult, just a bit annoying to work with and less intuitive. Also, Solidity's assembly is pretty high level compared to the assembly code your machine use.

I want to cover more assembly in the future because it is very helpful. Solidity is still a very new language and has a long way to evolve, so knowing how to build your own tools is important.
For instance, there is a guy on Github that built his own library to extend the functionalities of the native data types
https://github.com/willitscale/solidity-util

Curriculum

Beneficiaries

This post has as beneficiaries
@utopian.pay with 5%
using the SteemPeak beneficiary tool

image.png

Sort:  

Thank you for your contribution @igormuba.

Excellent work in the development of this tutorial, continue with good tutorials.

We are waiting for your next tutorial.

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Thank you for your review, @portugalcoin! Keep up the good work!

Hi, @igormuba!

You just got a 0.24% upvote from SteemPlus!
To get higher upvotes, earn more SteemPlus Points (SPP). On your Steemit wallet, check your SPP balance and click on "How to earn SPP?" to find out all the ways to earn.
If you're not using SteemPlus yet, please check our last posts in here to see the many ways in which SteemPlus can improve your Steem experience on Steemit and Busy.

Hi @igormuba!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Hey, @igormuba!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.19
TRX 0.15
JST 0.029
BTC 64036.76
ETH 2647.26
USDT 1.00
SBD 2.78