Ethereum transaction, bird’s-eye view

Verify.as
verifyas
Published in
5 min readOct 17, 2017

This is the fifth in a series of posts where we discuss the core concepts behind the Blockchain, Bitcoin and Ethereum. At Verify, we’re building a reputation protocol on the Ethereum blockchain and are sharing these posts in an effort to share our knowledge with the wider crypto community.

We have been introduced to Ethereum in the previous post, in this post we will explore transactions. Transactions can be as simple as transferring ether between two externally owned accounts or as complex as multiple contract-to-contract transfers.

A simple transfer example can be (note the JSON format):

eth.sendTransaction({from: ‘0xCBDB4E32a092203567487DAE4Abf66a7a7cbEE63’, to: ‘0xa8ade7feab1ece71446bed25fa0cf6745c19c3d5’, value: 1000000})

The value field defaults to “wei”; to use ether instead, it should go through the conversion function

web3.toWei(0.00…01, “ether”)

When a transaction takes place, the first thing to happen is it goes through a series of validations similar to that in Bitcoin, like verifying that the sender exists and the signature is valid.

An important side note to keep in mind is that contracts do not have private keys; this means that messages that call other contracts or functions do not need to be signed. It doesn’t require a signature because the transaction is already signed by the sender. Hence, a contract just verifies that the message is coming from a verified sender and executes its code.

After validation of the transaction, the next step is fee calculation. To find the total fee, simply multiply STARTGAS and GASPRICE. This total is deducted from the sender’s account. If there is enough balance to cover the cost of executing this transaction it will continue; otherwise an error is returned.

GAS will then be set to the value in STARTGAS, and some fees are deducted for the data stored in the transaction if any (remember each bytes is 5 gas).

The transaction value is then transferred from the sender’s account to the receiving account. If the receiving account does not yet exist, it will be created. If the receiving account is a contract, then the contract’s code will execute either to completion or until the execution runs out of gas.

If the value transfer failed because the sender did not have enough balance, or the code execution ran out of gas, all state changes are reverted except the payment/fee for running the transaction — which is sent to the miner’s account. After all, the miner spent computing resources executing this transaction.

The remaining gas will be refunded to the sender; again after deducting the execution fee that goes to the miner. Something to keep in mind and is that if you send off a transaction with low STARTGAS that is not enough to carry out the full transaction then the miner will run it until an “out of gas” exception is raised; at that point, all changes will be reverted, except that the gas will not be returned to you. It will be given to the miner for running that part of the transaction.

By now it is clear that transactions fired from externally owned accounts sets all action in Ethereum blockchain in motion. Without it, no action takes place. Whenever a contract receives a transition, its code get executed per parameters in the transaction. The code in the contracts is executed by the Ethereum Virtual Machine (EVM) that is running on the miner or the node connected to the network. EVM exists in the nodes’/miners’ environment. EVM runs EVM code, a stack-based bytecode language. Each byte in the code represents an operation.

The code execution is an infinite loop; that repeatedly carries out operations at the current program counter which keeps incrementing by 1 (starts at 0 when code execution starts and increments as operations get executed in the code). It continues until the end of the program is reached or an error, STOP or RETURN is encountered.

The operations have access to 3 types of spaces to store data (aside from its capability to access the received data like sender id..etc):

- The stack, a volatile last-in-first-out container to which values can be pushed and popped (it resets after computation ends)
- Memory (resets after computation ends)
- The contract’s long-term storage, a key/value store. (long term storage that persists beyond the transaction execution lifetime).

Let us take an example, suppose there is:

{a transaction with 10 ether,
GASPRICE being 0.001 ether,
STARTGAS is 2000 gas,
the data field has 64 bytes.
}

Let us start with the assumption that the transaction is from an externally owned account to another externally owned account. After the necessary validations, we calculate the cost of executing the transaction. The cost would be transaction length in bytes * GASPRICE and that is about it.

Now suppose the transaction is to a contract. This would be carried out somewhat differently:

After the necessary validations of signature and the likes, we then need to multiply GASPRICE and STARTGAS. So 0.002 * 2000 = 4 ether (Worth noting that 0.002 ETH (or 2,000,000 Gwei) is a ridiculously high GASPRICE! A more reasonable value would be 20 GWei).

We now check the balance of the sender. Assuming it has enough, we go ahead and initialize gas with 2000 gas.

Now we need to deduct the storage fees. We get the transaction number of bytes. Assuming the total number of transaction bytes is 150 bytes (64 of which is of data), we know for every 1 bytes we subtract 5 gas. So 150 * 5 = 750 gas.

By now we are left with 1250 gas. Now we subtract the 10 ether of the transaction from the sender’s account and send it to the contract, the contract’s code will run (assuming its code is to store the data sent to it) we store the data sent to the contract (the 64 bytes) assuming the contract’s code takes up 200 gas. So 1250–200 = 1050 gas.

Now that is 1050 *0.002 = 2.1 ether left from the original 4 ether. That would be given back to the sender’s account.

Have I been talking “transactions” only? In the previous post we’ve seen that there are transactions and messages; for a second there, you may have thought that I forgot about messages, but I did not!

Messages work similar to transactions in a way; when there isn’t sufficient gas, the execution terminates reverting back changes but still charging for execution. The question is how do you revert a message?

Recall the components of the message in the previous post? it has it’s own STARTGAS; so when it is out of gas it reverts back to its parent.

When a contract messages another contract with a specified STARTGAS the caller will lose that STARTGAS from its balance (if it was not fully consumed by the recipient contract, the remaining will be returned to the caller). Say in our previous example we had 1050 gas left now the contract A (current contract) calls another contract B with STARTGAS 150 gas, so the message will be off to contract B and contract A now has 1050–150 = 900 gas left. Assuming B used 50 gas, 100 will be returned to A so now A will have 1000 gas..

If B required more than 150 gas; its execution will be terminated when that gas is exhausted and control will be reverted to A. A will still have 900 gas left.

That is a birdseye view on how things move around in Ethereum. Fascinating, isn’t it?

--

--