0% found this document useful (0 votes)
18 views

1 Basic Introduction and Overview

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

1 Basic Introduction and Overview

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 27

Introduction to Smart Contracts and Solidity

blog.finxter.com/introduction-to-smart-contracts-and-solidity

June 29, 2022

In this first article in the series, we’ll start with the basics of what Solidity is, what smart
contracts are, how they work, how they are implemented, and then dig right into some
cool Solidity examples and details.

Terminology
Of course, the first question poses itself: what is Solidity?

As you could have imagined, Solidity has something to do with smart contracts. Solidity is
the very programming language we’ll be using for implementing smart contracts!

How exciting, isn’t it?

A simple, yet comprehensive and on-target definition of a smart contract states:

Definition: “Smart contracts are computer programs stored on a blockchain that run
when predetermined conditions are met. They are typically used to automate an
agreement‘s execution so that all participants can be immediately certain of the
outcome, without an intermediary’s involvement or time loss. They can also automate a
workflow, triggering the next action when conditions are met.” — IBM

At this point, I’ll point out several key concepts emerging from this
definition: programs, blockchain, conditions, agreement
automation, participants, outcome, and no intermediary.

A somewhat more technical definition says:

Definition: “A ‘smart contract’ is simply a program that runs on the Ethereum blockchain.
It’s a collection of code (its functions) and data (its state) that resides at a specific
address on the Ethereum blockchain.” — Ethereum.org

From this definition we can take a few more key concepts, this time from a technical
perspective: code, functions, data, state, and address.

During our exploration of Solidity, we’ll come upon these key concepts and explain their
meaning and role in the smart contract context.

What is Solidity?
Solidity is a high-level, object-oriented programming language, meaning its level of
abstraction is well above the physical layer of the machine(s) and platforms it runs on.

1/5
It will hide away all the intricacies of the underlying hardware and communication
networks, enabling us to focus on the ultimate functionality.

Variables, objects, types, functions, and other language constructs will be our building
blocks and stepping stones for creating even more exciting components which, when
connected, will form our smart contracts.

The object-oriented property of the language is just the characteristic that facilitates the
natural transfer of real-world entities and their behaviors into our models, finally
represented and deployed as smart contracts.

With its fragrance reminding of C++, Python, and JavaScript, Solidity is statically typed,
with support for inheritance (think of a smart contract as a class), libraries, and complex
user-defined types (docs).

Solidity contracts run on Ethereum Virtual Machine or EVM. This article (and the ones to
follow) will build on the official Solidity documentation, which I encourage you to regularly
check out at docs.

As indicated by the URL, at the time of writing this article, the current Solidity version is
v0.8.15 and unless explicitly stated otherwise, we will stick with it throughout the entire
series.

Typical examples of smart contracts we can implement by using Solidity are voting,
crowdfunding, blind auctions, multi-signature wallets, escrow arrangements, and many
others.

Smart Contract in Solidity – An Example


A simple, yet illustrative example of a smart contract enables us to notice the basic
elements of a smart contract implementation in Solidity:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
contract SimpleStorage
{
uint storedData;
function set(uint x) public
{
storedData = x;
}
function get() public view returns (uint)
{
return storedData;
}
}

2/5
Our first example shows a short smart contract implemented in Solidity, which does only
two things: it publicly enables storing a value in a state variable storedData via function
set and makes it publicly available for reading via function get.

However, the simplicity of our example will introduce us to the basic contract structure
and the most common language constructs used in a process of building smart contracts.

The line // SPDX-License-Identifier: GPL-3.0 states that the source code is licensed
under the GPL version 3.0. You can learn more about software licensing models at

https://www.gnu.org/licenses/gpl.html and
https://www.ivanti.com/blog/software-license-types.

The line pragma solidity >=0.4.16 <0.9.0; establishes the range of Solidity compiler
versions supporting the source code execution, ranging from (including) Solidity v0.4.16
up to, but excluding, Solidity v0.9.0. In the general case, the pragma keyword represents a
compiler directive specifying how to treat the source code.

In our specific case, it designates the compiler versions which are compatible with our
source code.

Note: I would like to point out a simple, yet practical detail: an open curly brace can be
placed in the same line with the contract name, and that’s the style I usually prefer in
other languages because it saves one line of code per block, making the code more
compact without sacrificing readability. However, when it comes to Solidity, code
readability benefits from placing the opening curly brace below the function head. Later
on, when we introduce function modifiers, it will be much easier to notice at a first glance
if we’re looking at the head or the body of a function. Of course, we could also mix the
two styles depending on the situation, but in the spirit of consistency, I recommend
keeping the opening curly brace in its line.

Content-wise, a contract is a collection of code and data. The code represents the
behavior of a contract which we modeled upon a real-world entity, and it is implemented
via functions.

The data represents the state of a contract and it is implemented via different types
of objects, making the contract a stateful entity.

The data resides in storage, a memory space mapped to an address on the Ethereum
blockchain.

The line contract SimpleStorage defines the name of our contract, SimpleStorage,
which we’ll also refer to as the head.

Next is a contract body marked opening “{” and closing “}” curly braces. We will also use
this head/body reference convention for other block constructs, such as functions.

3/5
The line uint storedData; declares a state variable called storedData of type uint
(unsigned integer of 256 bits in length).

storedData can be read and written to, resembling a rudimentary database-like behavior.
In our example, there are two functions, get and set, which read from and write to the
variable storedData.

The line function set(uint x) public declares a public function set, which takes an
unsigned integer x. The function without a keyword returns does not return a result.

The line storedData = x; assigns a value stored in the argument variable x to the state
variable storedData. A function without a state mutability keyword is considered to have
an implicit, default state mutability non-payable (explained below).

The line function get() public view returns (uint) declares a public function get,
which can only read the state variables from its outside scope because of the visibility
keyword view (explained below). The function also must return an object, i.e. a result of
type uint.

The line return storedData; returns the object storedData.

Visibility and State Mutability


Functions can be and often are augmented with a visibility keyword.

Both get and set functions are declared with the visibility keyword public, meaning that
the functions are callable from (visible to) the parent contract and all the other contracts.

There are three more visibility keywords: private, internal, and external.

The visibility keyword private makes the function callable only from inside the
parent contract.
The visibility keyword internal makes the function callable from the parent contract
and all the inherited contracts.
The visibility keyword external makes the function callable only from the other
contracts, and not from the parent contract.

Along with the visibility keywords, there are also three explicit state mutability keywords:
pure, view, and payable. These state mutability keywords determine if a function can
access or modify the objects (state variables) in its outside scope.

Keyword pure prevents the function from accessing its outside scope entirely,
meaning the function can access only its internal objects and its arguments.
Keyword view prevents the function from changing its outside scope, meaning the
function can access its outside scope objects (the contract state), its internal
objects, and its arguments.

4/5
Keyword payable enables the function to receive Ether, change its outside scope
objects (the contract state), its internal objects, and its arguments. The default state
mutability non-payable is implicitly assumed if no mutability keyword is specified,
and in that case, the function can change its outside scope objects (the contract
state), its internal objects, and its arguments.

Note: Function defined as pure partially resembles a pure function in functional


programming paradigm by having the second of the two important properties:

1. the function returns identical values for identical arguments;


2. the function has no side effects, i.e. it does not modify its outside scope. If a Solidity
function defined as pure would have both properties, it would be considered truly
pure in terms of the functional programming paradigm.

There will be a lot more details regarding visibility, state mutability, and their implications
in the upcoming articles, but until we build more knowledge, we’ll stick with the general
overview.

More details can also be found at the link describing the language grammar, and I
strongly recommend an in-depth look at the language possibilities.

Conclusion
In this article, we introduced ourselves to the basics of smart contracts and Solidity.

First, we peeked into some of the key concepts and terms in the realm of smart contracts
and Solidity.

Second, we got to know what Solidity is and what kinds of wizardry we can use it for.

Third, we ventured through a short example of a smart contract and saw some of its
spells – many more await us on our journey.

Fourth, we faced the most common Solidity magic, cast by visibility and state mutability.

5/5
How to Create Your Own Token in Solidity – Easy
Example
blog.finxter.com/creating-a-token-contract-in-solidity-easy-example

July 24, 2022

How to Create Your Own Token in Solidity - Easy Example

In the previous article of this Solidity crash course, we saw some of the basic elements of
Solidity concerning smart contracts.

In this article, we’ll be going even further with the examples and explanations, helping us
understand why, when, and how are specific elements of Solidity used in a certain way.

Also, as we continue our exploration of Solidity, we’ll introduce new concepts and clarify
their use. I can imagine you’re anxious to start, so let’s go!

Subcurrency Example
In this example, we’ll take a look at a bit more complex example of a smart contract (see
docs), which showcases a very basic form of cryptocurrency.

The contract provides its creator with the functionality of creating new crypto coins (some
may call them “shitcoins” ;)).

This example of a smart contract is implemented in a way that enables any party to send
coins (message sender) to any other party (message receiver) without being registered
with a username and password. The only factor that identifies a user is an Ethereum
keypair.

I’ll always break down more extended examples like the current one into smaller, more
manageable chunks, followed by an explanation of what each chunk does.

This way, it will be very easy to follow and understand what is going on in the source
code.

On a personal note, I’m aware that larger blocks of unfamiliar code can sometimes feel
overwhelming at first sight, especially when you’re not used to reading source code
written by another author. When that’s the case, my word of advice is: just give yourself
time and you’ll understand everything. Usually, at first, you’ll understand the code, and
then you’ll get the idea behind the code.

Here is our simple cryptocurrency smart contract:

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract Coin

1/6
{
// The keyword "public" makes variables
// accessible from other contracts.
address public minter;
mapping (address => uint) public balances;
// Events allow clients to react to specific
// contract changes you declare.
event Sent(address from, address to, uint amount);
// Constructor code is only run when the contract
// is created.
constructor()
{
minter = msg.sender;
}
// Sends an amount of newly created coins to an address
// Can only be called by the contract creator.
function mint(address receiver, uint amount) public {
require(msg.sender == minter);
balances[receiver] += amount;
}
// Errors allow you to provide information about
// why an operation failed. They are returned
// to the caller of the function.
error InsufficientBalance(uint requested, uint available);
// Sends a number of existing coins
// from any caller to an address
function send(address receiver, uint amount) public {
if (amount > balances[msg.sender])
revert InsufficientBalance({
requested: amount,
available: balances[msg.sender]
});
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
}

The Magic – Line by Line


As before, our first line starts with a license declaration, setting the license to GPL 3.0.

The line pragma solidity ^0.8.4; instructs the compiler to allow the source
compilation, not below the version 0.8.4 and strictly below 0.9 (the ^ symbol), i.e. the
upper version limit is set to the first major version.

2/6
Learn More: You can learn more about the Solidity file layout and pragma in this article on
the Finxter blog.

The line contract Coin starts the code block for our contract. I’ve put the opening curly
brace on the line below. The closing curly brace will end the code block for our contract,
and all our contract source code will fit in between.

The line address public minter; declares a variable named minter which will store the
coin minter’s address. The variable’s visibility is defined as public, making it accessible
from other contracts.

The line mapping (address => uint) public balances; declares a mapping object
between two variables of type address and type uint, i.e. unsigned integer. We could
perceive a mapping object as a dict object in Python, where we use an address as an
indexing element, and the uint object is the result that gets retrieved via the index
reference. The mapping object’s visibility is also set to public.

The line event Sent(address from, address to, uint amount); declares an event
that enables reactions to specific contract changes. In general, events are convenience
interfaces with the EVM logging facilities, which are commonly used in debugging.

On the next line, we have a constructor block, which is executed when a contract is
created. A constructor block can contain any amount of code, but in our case, it only has
one line, assigning the sender/account address to the variable minter:

constructor()
{
minter = msg.sender;
}
In the following block, we have a mint() function that “creates” new coins (out of thin air)
and sends (assigns) them to a receiver. Specifically, the function only increases the
amount available to a receiver. Only the contract creator is allowed to mint the coins, and
we have ensured such behavior by using a convenience function require, which checks if
the requirement is satisfied.

The require function is a convenience function, and it will create an error without any
message, or it will throw an error of type Error(string) if a string is passed to it. The
require function is commonly used to ensure valid conditions that cannot be detected
until the execution time, i.e. conditions received as function arguments or return values
originating from calls to external contracts.

function mint(address receiver, uint amount) public


{
require(msg.sender == minter);
balances[receiver] += amount;
}

3/6
The line error InsufficientBalance(uint requested, uint available); declares a
custom error object used below with the require function. In case, the error gets invoked,
we will see the error details showing the values of all received parameters, i.e. requested
and available.

In the following line, we have function send(address receiver, uint amount), a


function which will implement the logic for sending the specified amount to the receiver,
and it will simultaneously deduct the same amount from the sender, given the amount
being sent does not surpass the available amount on the sender’s account.

This behavior is implemented by the checking logic, which reverts the operation with our
custom InsufficientBalance error. The use of named parameters requested and
available assigned with amount and balances[msg.sender] is also introduced:

if (amount > balances[msg.sender])


revert InsufficientBalance({
requested: amount,
available: balances[msg.sender]
});
balances[msg.sender] -= amount;
balances[receiver] += amount;
The final line emit Sent(msg.sender, receiver, amount); reacts to a contract change
(as we previously mentioned in our initial explanation) by sending a signal, i.e. a Sent
event.

The Sent event carries the information about the message sender, the message receiver,
and the amount deducted from the message sender / added to the message receiver.

Events

Blockchain Basics of Smart Contracts and Solidity

By using a line emit Sent(msg.sender, receiver, amount); we have declared an


event, which is emitted when the send function executes the last line.

Web applications and other Ethereum clients can catch this type of event emitted on the
blockchain at a very low cost (in terms of used gas).

When an event is emitted, the listener (defined as a Javascript code that will follow
shortly) will receive the event, i.e. the arguments msg.sender, receiver, and amount
which are passed to the parameters from, to, and amount, which we’ve defined when we
declared our event Sent.

These arguments enable us an insight into the execution of the transaction.

The Javascript code for our event listener is also available from the GitHub repository:

4/6
Coin.Sent().watch({}, '', function(error, result) {
if (!error) {
console.log("Coin transfer: " + result.args.amount +
" coins were sent from " + result.args.from +
" to " + result.args.to + ".");
console.log("Balances now:\n" +
"Sender: " + Coin.balances.call(result.args.from) +
"Receiver: " + Coin.balances.call(result.args.to));
}
})
Since there are still some prerequisites in terms of the knowledge needed to set up our
local development environment and create and use the listener, we will postpone the
process and use the code above in one of the future articles.

Now, let’s just remember that the key library in use is the web3.js library – it is the main
JavaScript library to interact with the Ethereum blockchain.

Conclusion
In this article, we looked at a second one, a more complex example of a smart contract,
simulating a currency subcontract, which showed some of the common operations in coin
minting and sending.

First, we encouraged ourselves to take a first look at someone else’s source code
and survive in the process.
Second, we got to know the code very closely, as it got friendlier and tamer with
each step.
Third, we learned how to deliberately make, errr… define an error and use it to
make our code even more stable and trustworthy.
Fourth, we produced a streak of lightning at the end of our smart contract by
emitting the Sent event and by doing so signaled that everything went fine.

What’s Next?
This tutorial is part of our extended Solidity documentation with videos and more
accessible examples and explanations. You can navigate the series here (all links open in
a new tab):

Prev Tutorial
Syllabus
Next Tutorial

Learn Solidity Course


Solidity is the programming language of the future.

5/6
It gives you the rare and sought-after superpower to program against the “Internet
Computer”, i.e., against decentralized Blockchains such as Ethereum, Binance Smart
Chain, Ethereum Classic, Tron, and Avalanche – to mention just a few Blockchain
infrastructures that support Solidity.

In particular, Solidity allows you to create smart contracts, i.e., pieces of code that
automatically execute on specific conditions in a completely decentralized environment.
For example, smart contracts empower you to create your own decentralized
autonomous organizations (DAOs) that run on Blockchains without being subject to
centralized control.

NFTs, DeFi, DAOs, and Blockchain-based games are all based on smart contracts.

This course is a simple, low-friction introduction to creating your first smart contract using
the Remix IDE on the Ethereum testnet – without fluff, significant upfront costs to
purchase ETH, or unnecessary complexity.

6/6
Blockchain Basics of Smart Contracts and Solidity
blog.finxter.com/introduction-to-smart-contracts-and-solidity-part-3-blockchain-basics

August 3, 2022

This article will give you an overview of the blockchain basics, transactions, and blocks.

In the previous article of this series, we looked at how to create your own token using
Solidity and, specifically, events for transactions.

Blockchain Basics of Smart Contracts and Solidity

Blockchain Basics
Blockchain technology enables us to write programs without having to think about the
details of the underlying communication infrastructure.

However, just to be aware of some of the keywords which are commonly used when
studying the infrastructure, we’ll name just a few among others (borrowed from the
Solidity documentation):

mining,
elliptic-curve cryptography,
peer-to-peer network.

Although it’s interesting to see how these technologies work “under the blockchain’s
hood”, the beneficial fact is that you don’t have to be closely familiar with them. You can
just implicitly utilize them and maybe even forget they’re there. However, they represent
some of the key elements which make up Web3.

Note: Here, we need to establish a firm distinction between the terms Web3 in the
blockchain context that is the subject of our interest when discussing Solidity, and the
Semantic Web, sometimes known as Web 3.0, which is an extension of the World Wide
Web, intended to make Internet data machine-readable.

Transactions
One of the main roles of a blockchain is to preserve the data and make it temper-
resistant. In that sense, we can easily consider a blockchain as a globally shared,
transactional database.

A blockchain network is globally shared because any party in the network can access
and read its contents.

It is transactional because any change to the blockchain has to be accepted by almost


all, or at least the majority of other members, depending on the blockchain
implementation.

1/5
In database theory and practice having a transactional property means two things: the
change to the database is either applied completely or not at all (see here); no other
transaction can modify the effect of a transaction being executed.

We regularly ensure the equivalent behavior of our smart contracts by using error
handling and control structures available in Solidity (docs).

Blockchain Security
There is also a strong security property that is inherent in the way how blockchain works:
each new block header includes the hash of the previous block.

To alter a block in a blockchain, an attacker would have to re-mine the targeted block and
all the following blocks, therefore creating a chain fork.

Also, an attacker would need to invest more total work than was invested in the original
chain segment to get his chain fork accepted by the rest of the network (source).

The latter would require immense computing power and energy, making the entire effort
unfeasible in theory.

However, there have been successful attacks on blockchain networks, mostly due to the
smaller scale of a particular network, where a fraudulent consensus (the verification
process) was less difficult to fabricate, block creation errors, or insufficient security
measures (source).

Example Application
An example to the story above is already given in part by the example we did in the
previous article: a smart contract for (simulated) currency transfer between any two
parties.

There was a list of accounts holding balances in a cryptocurrency, Wei, and our smart
contract supported transfers of a given amount of currency from the sender to the
receiver.

What’s important in the context of such transactions is that the same amount of currency
should always be “simultaneously” deducted from the sender’s account and added to the
receiver’s account.

What we mean by “simultaneously” is not a matter of happening at the same moment, but
happening with the same, but the opposite consequence, i.e. if the amount gets
successfully deducted from the sender’s account, it has to be added to the receiver’s
account.

If an error occurs after the amount is decreased from the sender’s account, but before the
amount is added to the receiver’s account, the operation should revert to the smart
contract’s previous state, as it was before the transaction started.

2/5
This way, the blockchain behaves in a consistent, transactional manner and
warrants that the transaction will be done entirely or not at all.

In the context of everything said so far, with our subcurrency example in mind, we may
ask ourselves:

Question: How would we enable an account owner to transfer the currency only from the
account in his ownership?

The answer to the question is relatively simple:

Answer: A transaction always bears the sender’s cryptographic signature, which serves
as a seal in granting access to precisely defined modifications of (operations on) the
database, such as currency transfer from the account owner originally holding the
currency, to the account owner – receiver of the currency.

Blocks
There is no story about blockchain without actually mentioning the block itself. We will
definitively return to talk about a block from some other angles, but with a security
perspective in mind, we will focus on overcoming a significant obstacle known (in Bitcoin
terms) a “double-spend attack” (source).

Some paragraphs ago, we mentioned a blockchain attack implying the majority of the
network members’ acceptance, popularly known as the “51% attack”.

Let’s assume there are two transactions in the blockchain network, and each of them
attempts to transfer all the account’s currency to another account, i.e. they will both
attempt to empty the account.

Since there can be only one accepted, confirmed transaction (in contrast to two or more
possible unconfirmed transactions), the transaction that gets confirmed first will end up
bundled in a block. It is not under our control or, for that matter, not even a subject of our
concern which block will be the first one.

What matters is that the second block will be rejected and the contention between the
blocks/transactions will be resolved automatically, and the likelihood of the double-spend
attack problem will decrease with each additional confirmation (source).

Blocks are sequentially added to a blockchain, ordered by the time of their arrival. Adding
a block to the blockchain is mostly done in regular intervals, which last about 17 seconds
for the Ethereum network.

Nonetheless, the blockchain tip can sometimes be reverted during the order selection
mechanism. In that case, a confirmed block will get discarded and become a stale block,
and the stale block’s successor blocks just get returned to the memory pool.

Note: discarded or stale blocks are popularly and wrongly called orphan blocks. (source)

3/5
For block reversal to happen, two conditions should occur.

(1) First, multiple blocks should get created from the same parent block P simultaneously
(by different miners) and get confirmed by the network, forming a fork with multiple
subchains/branches at the tip (block) P of the blockchain.

As there are multiple successor block candidates (e.g. we will assume three blocks, A, B,
and C), each block has an equal chance of becoming a permanent part of the blockchain.

Because blocks propagate through the blockchain network differently, miners will receive
one of the blocks (A, B, or C) before the other blocks and start mining a new block on the
block they received first.

(2) Second, one of the miners will mine and broadcast a new block, e.g. C1 to the
network before the other miners mine blocks A1 or B1 (these don’t exist as yet).

Since the fastest miner first received block C and then produced C1, it will extend the
branch P-C, effectively making the branch P-C-C1 the longest one. Once the network
detects there is a chain longer than the chains P-A and P-B, it will disqualify the candidate
blocks A and B as stale blocks, thus resolving the contention.

All the miners who chose a different blockchain from the fork, e.g. P-A or P-B, and started
building their blockchains on them, will experience a block reversal, as their chains will
also get updated by the network with the blockchain P-C-C1 as the longest one.

The blockchain tip reversal gets less likely to happen as more blocks are confirmed and
added to the blockchain. A common number of confirmations after we can be virtually
certain that our block became a permanent part of a blockchain is six confirmations
(source).

Conclusion
In this article, we first shortly made a short detour (sorry about that) to a missing part
about Solidity events, and then boldly stepped into the direction of blockchain basics,
transactions, and blocks.

First, we made friends with an event listener example based on web3.js library.

Second, we glanced at the blockchain basics. You already know the works: some basic
terms, dry notes, etc. It’s just a scratch, really.

Third, we learned about how blockchain treats transactions and how it makes them feel
secure, shared and cared for. That’s why we mentioned some properties that make
blockchain look like a database.

Fourth, we went into some light details on what a block is, what is its role in the
blockchain ecosystem and what are some of the risks present in a blockchain network.

4/5
In particular, Solidity allows you to create smart contractsdecentralized autonomous
organizations

NFTs, DeFi, DAOs, and Blockchain-based games are all based on smart contracts.

This course is a simple, low-friction introduction to creating your first smart contract using
the Remix IDE on the Ethereum testnet – without fluff, significant upfront costs to
purchase ETH, or unnecessary complexity.

5/5
Mastering the Ethereum Virtual Machine (EVM) for
Solidity Smart Contracts
blog.finxter.com/mastering-the-ethereum-virtual-machine-evm-for-solidity-smart-contracts

August 14, 2022

Mastering the Ethereum Virtual Machine (EVM) for Solidity Smart Contracts

In this article, we will make a more thorough insight into the Ethereum Virtual Machine
through general terms such as accounts, transactions, and gas.

Although it may seem challenging, it will bring us much closer to our main goal: we will
learn more about our favorite technology and improve our coding skills further
down the road by building on the understanding of the core principles.

Before you scroll through the article, feel free to get a quick overview by scrolling through
our PDF slides:

Finxter-Solidity-Crash-Course-EVMDownload

The Ethereum Virtual Machine – An Overview


The Ethereum Virtual Machine, or as we will usually call it by its pet name, EVM,
represents a runtime environment for Ethereum smart contracts.

For those of us who may be unfamiliar with the term, a runtime environment represents a
computer infrastructure that enables a computer program execution. It usually consists of
a software section (instruction set and software libraries) and a hardware section (working
memory, storage, and a network).

An application runtime environment can have several flavors.

The most basic one is a bare-metal runtime environment, providing complete,


unrestricted access to the underlying hardware and software resources of a physical host.
This type of runtime environment is very rarely in use.

More complex and manageable runtime environments use an abstraction of physical host
software and hardware resources and restrict an application from accessing the
resources directly.

When physical host resources are managed and accessed in such a way, we consider
them to be virtualized environments. From a resource accessibility, i.e. security
perspective, virtualization can provide a sandboxed or isolated runtime environment. The
difference lies in what an application can do when it runs.

1/6
A sandboxed application can access virtualized resources, such as network, filesystem,
or other running applications’ processes. An isolated application is completely restricted
from accessing anything other than its own process instance, and with possible
exceptions, some other subset of running processes.

In that sense, an EVM runtime is an isolated one, enabling only limited access to other
smart contracts.

Accounts
The EVM, and by extension, Solidity support two kinds of accounts in Ethereum: the
external accounts and the contract accounts. Both kinds of accounts share the same
address space, but they also differ in the way they are controlled.

The external accounts are controlled by public-private key pairs, i.e. humans.

For the more interested among us, I recommend checking out the topic of asymmetric
cryptography. I won’t go into much detail about it, but I’ll give a coarse summary:
asymmetric cryptography implies a key pair where one of the keys is used for encryption,
and the other one is used for decryption.

The emphasis is on this crucial property: a single key cannot be used for both
encryption and decryption in the same <plain data> encryption <encrypted data>
decryption <plain data> operation sequence. You’ll choose one of the keys as a public
key and share that key with the world; the other key will be your private key.

Info: a key’s ownership role (public or private) doesn’t determine its cryptographic role,
i.e. both keys can be used in different encryption and decryption operation sequences.

In contrast to external accounts, contract accounts have their code attached to them, and
the code (behavior) is what controls the contract account.

In the case of an external account, a public key determines the contract’s address. In the
case of a contract account, its address is calculated at the time of the contract’s creation,
based on the contract creator’s address and a nonce, i.e. a number of transactions sent
from the contract creator’s address.

Definition: A nonce is a neologism (a new-coined word), meaning a “number used once”.


A nonce, or to be more specific, a cryptographic nonce is a random or semi-random
number used in many cryptographic processes. It ensures that there are no reused
values when a process requires randomness.

From another point of view, we could make a simple distinction between the two account
types by noticing that the contract accounts store code, and the external accounts don’t
store code. EVM considers both types of accounts to be equivalent.

2/6
Every account is equipped with a persistent key-value memory object – storage, that
maps 256-bit words to 256-bit words. Also, every account has a balance expressed in
Ether’s sub-currency Wei, which gets modified by sending transactions that include Ether.
One unit of Ether consists of 1018 units of Wei.

Transactions
Accounts exchange messages to communicate in both directions, and a term transaction
means one message exchanged in a communication session.

A transaction can be empty, it can also contain some binary data called payload,or it can
carry Ether (Wei).

When a transaction is sent to a contract account, the contract account code is executed,
and the transaction payload is interpreted as the contract input data.

If a transaction with a payload is being sent without specifying the recipient account (or if
the recipient is set to null), the transaction will result in creating a new contract with an
address calculated as we previously described.

In a described case, the payload is interpreted as EVM bytecode, and it is executed,


creating, in turn, the code in its final form required for a smart contract to run.

Summarized, what we start with is the smart contract source code, such as the one we
use in our code examples. The source code gets compiled to the EVM bytecode, which is
sent in a transaction, executed in an EVM runtime, and permanently stored as the code of
the contract.

Info: “Bytecode is computer object code that an interpreter converts into binary machine
code so it can be read by a computer’s hardware processor”. In general, bytecode is
intermediary code, usually produced after compiling the original source code. Probably
one of the most obvious advantages of using bytecode is semi-optimized, multiplatform-
portable code.

At first, the contract gets created, then the constructor gets executed, and only after the
constructor finishes the contract’s code is stored and available. Due to this delicate order
of steps, a contract may be referenced and called into only if the constructor finished
constructing the contract.

Gas
Contract-creating transactions and any other kinds of executed transactions are taxed
with a certain cost.

This cost is expressed in special units called gas (this type of economy slightly reminds
me of the one based on gasoline in a postapocalyptic movie classic Mad Max).

3/6
The gas units are paid for by the originator (initiator) of the transaction (we can view the
originator’s account address in the tx.origin variable).

As the transaction is executed on an EVM, the gas gets gradually consumed in steps,
according to a set of predefined rules. If case of an event when the entire amount of gas
gets depleted before the transaction completes (the available amount of gas becomes
smaller than zero, i.e. negative), the out-of-gas exception is raised, meaning that
transaction execution ends and all its state changes in the current call frame are reverted.

Reminder: remember (from the previous article of this Solidity Crash Course) that every
transaction ensures state consistency by successfully completing or reverting the
changes it made up to the point of an exception.

By now, we probably wonder why we even have to have gas metering and taxing. The
answer is made for two reasons.

The first reason lies in a need for economical use of the EVM’s execution time.
When a transaction takes a shorter time, it inherently consumes less gas, so the
transaction originator is incentivized to make the transaction as short as possible.
EVM execution is only possible because EVM executors, i.e. miners and stakers
invest their equipment’s time and energy in mining (validating) the transaction block
(every transaction is bundled in a block).
This brings up the second reason: the consumed gas also compensates the EVM
executors for their work. In other words, taxing the transaction originator works like
a blind auction: the EVM executors will naturally be more inclined to accept the
blocks that will provide them with a higher compensation = gas price * gas amount.
It is up to the transaction originators to set the gas price somewhere in the sensible
range to ensure their transaction block will be picked up and mined (validated) by
an EVM executor. In case the transaction originator foresaw more than enough gas
for the transaction, possible leftover gas will be refunded back to the transaction
originator.

However, the gas price auctioning cannot continue indefinitely, again, for two reasons.

First, there is a maximum amount of gas that can be charged for each block, so the
maximum amount of work invested in mining a block is limited.
Second, although the transaction originator may, in theory, set his gas price
arbitrarily high, at some point, the gas price would exceed the real economic value
represented by the transaction, so setting the gas price above that level would
make no sense, i.e. it would result in a loss for the transaction originator.
Third, we can easily recognize that it would make no sense to set the gas price too
low simply because the incentive for a transaction block would not be interesting
enough for an EVM executor to pick up the block and mine (validate) it.

Conclusion

4/6
In this article, we started creating a more detailed insight into the core principles of the
Ethereum Virtual Machine.

First, we acquired a taste for the Ethereum Virtual Machine as a runtime


environment.
Second, we started wondering about how cooking the books feels… Just kidding,
that’s not that kind of account, but nevertheless, it’s still very interesting and crucial
to understanding.
Third, we faced the almighty transactions and saw how they breathe and live. As it
turns out, it wasn’t so scary. Nonetheless, we’ll continue building on top of that
knowledge on the first possible occasion.
Fourth, we dipped our hands in gas and enjoyed the smell of knowledge we’ve
gotten for understanding how it drives the Ethereum network. And we also
remembered Mad Max.

Recommended Resources: Read the full Solidity Crash Course and check out our
Solidity course on the Finxter Academy.

What’s Next?
This tutorial is part of our extended Solidity documentation with videos and more
accessible examples and explanations. You can navigate the series here (all links open in
a new tab):

Prev Tutorial
Syllabus
Next Tutorial

Programmer Humor – Blockchain

5/6
“Blockchains are like grappling hooks, in that
it’s extremely cool when you encounter a
problem for which they’re the right solution,
but it happens way too rarely in real life.”
source – xkcd

6/6
Ethereum Virtual Machine (EVM) Message Calls –
Solidity Smart Contracts
blog.finxter.com/ethereum-virtual-machine-evm-message-calls-solidity-smart-contracts

August 19, 2022

Ethereum Virtual Machine (EVM) Message Calls - Solidity Smart Contracts

You can scroll through the presentation as you watch the video here:

In this article, we’ll hold the depth from the last article regarding the Ethereum Virtual
Machine through topics such as message calls and special variants of calls, logs,
callcode/delegatecall, libraries, logs, special operations for smart contract code
creation/removal, and finally, precompiled contracts.

This is Part 6 of our Solidity Crash Course:

Full Course Curriculum and Overview: Solidity Crash Course

Message Calls
Message calls are a mechanism to enable inter-contract communication, such as calling
other contracts or sending Ethereum to non-contract accounts.

Message calls are similar to transactions (exchange of messages) in that they also use
parameters source, target, data payload (input data), Ether, gas, and return data.

In terms of implementation, every transaction is nested


(https://nestingdolls.co/blogs/posts/meaning-symbolism-nesting-dolls), or more commonly
said, wrapped, in a top-level message call that can also create further message calls, e.g.
in a situation where additional messages need to be exchanged and calculations
performed before a transaction can finalize.

The contract has an additional role, and that is to set the amount of gas that will be
deducted from the outer (upper) message call before the remaining gas gets forwarded to
the inner (lower) message call. We have previously explained what an out-of-gas
exception is.

If any type of exception happens in an inner message call, the exception will put an error
value onto the stack, and only the amount of gas that was forwarded to the inner
message call is used.

In Solidity, the calling contract follows up on such situations by throwing an exception by


default, causing the exceptions to “bubble up” or emerge up the call stack.

1/5
Each time the called contract, i.e. a function gets called, it will be assigned with an
instance of (working) memory that lasts until the call ends. Such an instance is usually
known as a stack frame, activation frame, or activation record
(https://www.techopedia.com/definition/22304/stack-frame).

The memory instance will also receive the call payload, i.e. the (function) call arguments
via a separate memory area, the calldata. The called contract can return the data to a
memory location in the caller’s memory, which is preallocated by the caller. All message
calls are synchronous, meaning the caller contract (function) will wait until it receives a
reply from a called contract (function).

Note: A stack frame exists only during the contract (function) call and holds all the
information needed for a called function to execute and return to the caller. It enables
some important programming approaches, such as recursion.

Message calls can go 1024 levels in depth (that’s 1024 stack frames), meaning that we
shouldn’t use them for iterating over an array or performing more complex operations.
When we do require complex operations, loops are a tool of choice.

Besides that, there is also a limit on how much gas we can forward to a message call
(63/64 parts), practically limiting us further, to about 1000 levels in depth.

callcode and delegatecall and Libraries


Besides ordinary message calls, as described in a previous chapter, we have special
message calls available, named delegatecall and callcode.

These specific message calls might seem a bit strange, so we’ll go through step by step.

A callcode message call is very similar to an ordinary message call, except for one
crucial difference: the code from the called contract (at the target address) is executed in
the context of the calling contract (at the source address).

What this means is that the executed code behaves just like it was an integral part of the
calling contract.

Additionally, a delegatecall message call is identical to callcode, but it keeps the


variables msg.sender (current address) and msg.value (account balance) unchanged.

delegatecall and callcode message calls enable our contract to dynamically load the
code from a different address at runtime, effectively enabling us to import a remote
contract as a reusable library code and use it in our contract’s storage, e.g. for building
complex data structures.

Logs
Logs are a specially indexed data structure that provides us with logging functionality, with
logs saved in the Ethereum blockchain.

2/5
In one of the previous articles, we mentioned that logs are used by Solidity to implement
events.

The log data in the blockchain is partly stored in Bloom filters


(https://llimllib.github.io/bloomfilter-tutorial) unavailable to contracts, however, it can be
accessed from outside the blockchain, by the so-called light clients.

Light clients are network peers that do not download the whole blockchain but still can
search for log data stored in bloom filters in an efficient and cryptographically secure way.

Create
We have previously mentioned a catalog of EVM instructions, called the instruction set.

Each instruction is represented by an instruction mnemonic, which is “a word or acronym


used in assembly language to represent a binary machine instruction operation code”

(https://www.webster-dictionary.org/definition/instruction+mnemonic).

As the definition mentioned, there is also an operation code, or short, an opcode. An


opcode is a number that EVM uses to recognize specific instructions.

Among other opcodes, there is a special opcode create, that a contract can use to create
other contracts.

Of course, there is a small difference between ordinary message calls and those invoked
by create calls: the payload data is treated as code, therefore it gets executed. Upon
execution, the caller (creator) contract receives the return data, i.e. the address of the
newly created contract on the stack.

Self-destruct and Deactivate


We went through the creation of a contract, but what about its destruction?

Well, the contract can also be taken off duty, so to say, by removing its code from the
blockchain.

The code is removed when the contract at a certain address executes a selfdestruct
instruction, which will take care of the remaining Ether stored at that address, i.e. it will
move it to a specified receiver.

A call to selfdestruct may originate directly from the contract, or indirectly by using
instructions delegatecall or callcode.

In the next step, the contract’s storage and code are removed from the contract’s state.

Although the contract removal can also be done, it’s not recommended because if Ether
is mistakenly sent to a removed contract’s address, it will become lost and unavailable.

3/5
A better approach to deactivating contracts is disabling them by changing some of the
internal states which will cause all functions to revert. This way, such a contract will be
unusable, but the Ether will be immediately returned, instead of lost.

Note: selfdestruct instruction is not the same thing as the delete command we all know
and love (?), because a contract removed by calling selfdestruct will remain a part of
the blockchain’s history.

Precompiled Contracts
As a final chapter of this article, we will mention a special group of contracts, the
precompiled contracts.

They occupy a small range of reserved contract addresses between 1 and 8 (inclusive),
available for calling just as with any other contract.

However, these precompiled contracts’ behavior and gas consumption are not defined by
our code at these addresses. In fact, these addresses do not contain any code. Their
behavior and gas consumption are implemented in the EVM runtime environment.

Note: although all (future) precompiled contracts in the Ethereum main chain are
expected to land in the reserved address range between 1 and 0xffff (inclusive), there is a
possibility that different, but EVM-compatible chains may deviate, that is, use a different
set of precompiled contracts.

The Conclusion
In this article, we have gone through the EVM structure and gained a very good insight
into its core concepts, structure, and melody.

First and most important, Carly Rae Jepsen has a nice song like made for our main topic,
“Call Me Maybe”. It’s a great and cheerful song, as well as our message calls.

Second, we found out how a contract may dress in borrowed feathers – by codecall and
delegatecode! And while it was at it, it also joined the library.

Third, every self-respected lumberjack knows his logs. Now we do too.

Fourth, what’s the use of the logs, if we don’t know how to put them to good use? That’s
why we learned how to create – contracts! Although, digital, not paper ones… But they’re
smart!

Fourth, not the happiest part of the process, we also learned how to deactivate and self-
destruct. T-800 would be so proud of us because we’ll be back.

Fifth, if nothing else, “we’ll always have Paris”, that is, precompiled contracts. Some of
them will surely be in Paris. And now we share some beautiful memories with them.

4/5
5/5

You might also like