Overview of Smart Contracts

Overview

After roughly understanding the basic concepts of Bitcoin, it is much easier to understand the concept of Ethereum. The most important thing is to figure out what a smart contract is.

It’s just that the contract is actually a piece of code stored on the blockchain and running on the miner machine. Due to the limitations of Ethereum, this piece of code cannot be too large or too complex.

So how does a smart contract roughly work?

The current understanding is that there are two types of accounts in Ethereum, one is an external account and the other is a contract account. Both have their own addresses and balances. The only difference is that the contract account stores the codehash of the smart contract contract. The actual contract code has been stored on the blockchain by miners through a transaction, so publishing a contract is actually a transaction. A contract can be created by sending a transaction to an all-zero address, and then the address of the contract is generated according to the contract content to identify the contract account. This process is different from creating an external account. The generation of the external account address is to generate a private key with a public key, and then The address is calculated by the private key. This process is irreversible, which is why only mastering the private key is equal to mastering the address; however, the address generation of the contract account mainly relies on the hash of the contract code.

When we issue an instruction through the interface on the dapp, it may be to initiate a transaction to a specified contract account. After receiving the transaction message, the miner finds the contract code through codehash and runs it. Of course, the transaction can also be transferred to the contract account. After running the contract, the miner charges a certain fee on the basis of the transaction, and then can obtain the fee after confirming the transaction through mining.

It does not mean that every transaction must be sent to a certain contract account, or it can be directly sent to an external account. The miner who receives this transaction information only needs to confirm whether the transaction can be established, such as whether the sender’s simple balance is sufficient, without running the contract code.

We can simply understand DApp as a project with front-end and back-end separation. The front-end is the normal front-end we have seen at ordinary times, but his background code is a smart contract, and the communication between the two is not something we usually use. Similar to Axios, but through web3.js to communicate.

Detailed doc summary

What is a smart contract

Ethereum is a programmable blockchain application. Like Bitcoin, Ethereum is based on a peer-to-peer network protocol composed of distributed computers. However, Ethereum does not provide a specific function like Bitcoin. In fact, Ethereum does not provide any ready-made functions, including transactions. Instead, it allows users to program and develop functions on its own basis, and then develop the code. Stored on the blockchain and available to everyone, these programs run on the Ethereum Virtual Machine, that is, on a network composed of all Ethereum nodes. The computing power is provided by the entire Ethereum network, and the final computing power is actually provided. The nodes pay fees. These programs running on the Ethereum Virtual Machine are smart contracts.

There are a large number of computer nodes in the Bitcoin network responsible for maintaining and updating the blockchain, which also exist in ETH and are called EVM (Eth Virtual Machine). Think of EVM as a supercomputer with the computing power of all nodes in the network, which is used to run smart contracts on the blockchain. EVM charges users a very small ETH token maintenance fee in return to provide the computing power needed for smart contracts, which is called “gas”. So the core meaning of ETH tokens is not as a currency of general equivalents, but as a power to power the ETH network like oil.

Simple smart contract

We will explain through the example of the official website

Storage

1
2
3
4
5
6
7
8
9
10
11
12
13
pragma solidity ^0.4.0;

contract SimpleStorage {
uint storedData;

function set(uint x) public {
storedData = x;
}

function get() public view returns (uint) {
return storedData;
}
}

The first line tells you that the source code is written in Solidity version 0.4.0, and it is fine to run it with versions above 0.4.0 (up to 0.5.0, but not including 0.5.0). This is to ensure that the contract does not suddenly behave abnormally in the new compiler version. The meaning of the keyword pragma is that, in general, pragmas (compile instructions) are instructions that tell the compiler how to handle source code (for example, pragma once )。

The meaning of a contract in Solidity is a set of code (its * function *) and data (its * state *) located at a specific address on the Ethereum blockchain. The code line uint storedData; declares a state variable of type uint (256-bit unsigned integer) called storedData. You can think of it as a location in the database that can be queried and changed by calling the function that manages the database code. For Ethereum, the above contract is an owning contract. In this case, the functions set and get can be used to change or retrieve the value of the variable.

To access a state variable, a prefix like this. is not required, although this is a common practice in other languages.

This contract can accomplish not many things (due to the infrastructure built by Ethereum): it allows anyone to store a single number in the contract, and this number can be accessed by anyone in the world, and there is no feasible way to prevent you from publishing this number. Of course, anyone can call set again, pass in a different value, overwrite your number, but the number will still be stored in the blockchain’s history. Later, we will see how to impose access restrictions to ensure that only you can change the number.

** Comment **

All identifiers (contract names, function names, and variable names) can only use the ASCII character set. UTF-8 encoded data can be stored as string variables.

** Warning **

Be careful with Unicode text, because although some characters look similar (or even the same), their character codes are different, and their encoded character arrays will also be different.

** Subcurrency example **

The contract below implements the simplest cryptocurrency. Here, coins can indeed be created out of nothing, but only the person who created the contract can do it (it is not difficult to implement a different publish plan). Moreover, anyone can transfer coins to someone else without registering a username and password - all that is required is an Ethereum key pair.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
pragma solidity ^0.4.21;

contract Coin {
//The keyword "public" makes these variables readable from the outside
address public minter;
mapping (address => uint) public balances;

//Light Client can react efficiently to changes through events
event Sent(address from, address to, uint amount);

//This is a constructor function that only runs when the contract is created
function Coin() public {
minter = msg.sender;
}

function mint(address receiver, uint amount) public {
if (msg.sender != minter) return;
balances[receiver] += amount;
}

function send(address receiver, uint amount) public {
if (balances[msg.sender] < amount) return;
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
}

This contract introduces some new concepts, let’s read them one by one.

Address public minter; This line declares a state variable of type address that can be accessed publicly. The address type is a 160-bit value and does not allow any arithmetic operations. This type is suitable for storing contract addresses or key pairs for outsiders. The keyword public automatically generates a function that allows you to access the current value of this state variable outside of this contract. Without this keyword, no other contract can access this variable. The code for the function generated by the compiler looks roughly like this:

1
function minter() returns (address) { return minter; }

Of course, adding a function exactly like the above will not work, because we will have a function and a variable with the same name. Here, I mainly hope you can understand - the compiler has already implemented it for you.

The next line, mapping (address = > uint) public balances; also creates a public state variable, but it is a more complex data type. This type maps address to unsigned integers. Mappings can be seen as a 哈希表 It performs virtual initialization so that all possible existing keys are mapped to a value represented by bytes as all zeros. However, this analogy is not very appropriate because it can neither obtain a list of all mapped keys nor a list of all values. Therefore, either remember the data you added to the mapping (using list or higher-level data types would be better), or use it in contexts that do not require a list of keys or values, as in this example. And the getter function created by the public keyword getter function It is a more complicated situation, which is roughly as follows:

1
2
3
function balances(address _account) public view returns (uint) {
return balances[_account];
}

As you can see, you can easily check the balance of the account through this function.

Event Sent (address from, address to, uint amount); This line declares a so-called “event” that will be emitted on the last line of the send function. User Interface (and of course server applications) can listen to events being sent on the blockchain without much cost. Once it is emitted, the listener listening to the event will be notified. And all events contain three parameters from, to and amount, making it easy to track transactions. To listen for this event, you can use the following code:

1
2
3
4
5
6
7
8
9
10
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));
}
})

Note here how the automatically generated balances function is called from the User Interface.

The special function coin is a constructor function that runs during the creation of a contract and cannot be called after the fact. It permanently stores the address of the person who created the contract: msg (along with tx and block) is a magical global variable that contains some properties that allow access to the blockchain. msg.sender is always the source address of the current (external) function call.

Finally, the methods that are actually called by the user or other contract to complete the function of this contract are mint and send. Nothing happens if mint is called by someone other than the contract creator. On the other hand, the send function can be used by anyone to send coins to others (provided, of course, that the sender owns the coins). Remember, if you use a contract to send coins to an address, you won’t see any relevant information when you view the address on the blockchain browser. Because, in fact, the information you send coins and change balances is only stored in the data storage of specific contracts. By using events, you can very easily create a “blockchain browser” for your new coins to track transactions and balances.

Ethereum Virtual Machine

** Overview **

The Ethereum Virtual Machine EVM is the operating environment for smart contracts. It is not only sandbox-encapsulated, but also completely isolated, which means that code running in EVM cannot access the network, file system, and other processes. Even access between smart contracts is limited.

** Account **

There are two types of accounts in Ethereum (they share the same address space): ** external accounts ** controlled by public-private key pairs (aka people); ** contract accounts ** controlled by code stored with the accounts.

The address of the external account is determined by the public key, while the address of the contract account is determined when the contract is created (this address is calculated by the address of the contract creator and the number of transactions sent from that address, which is called “nonce”).

These two types of accounts are the same for EVM regardless of whether the account stores code or not.

Each account has a persistent storage in the form of Attribute-Value Pair. The length of both key and value is 256 bits, which we call ** storage **.

In addition, each account has an Ether balance (** balance **) (unit is “Wei”), and the balance will change due to sending transactions containing Ether.

** Transaction **

Transactions can be seen as messages sent from one account to another (accounts here may be the same or special zero accounts, see below). It can contain a binary data (contract payload) and ether.

If the target account contains code, this code will be executed with payload as the imported parameter.

If the target account is a zero account (the account address is 0), this transaction will create a ** new contract **. As mentioned earlier, the address of the contract is not a zero address, but is calculated from the address of the contract creator and the number of transactions sent from that address (so-called “nonce”). The payload of the transaction used to create the contract will be converted to EVM bytecode and executed. The output of the execution will be permanently stored as contract code. This means that in order to create a contract, you do not need to send the actual contract code, but send the code that generates the contract code.

** Comment **

During the process of contract creation, its code is still empty. So until the constructor function is executed, you should not call the contract’s own function in it.

Gas

Once created, each transaction is charged a certain amount of ** gas ** in order to limit the amount of work required to execute the transaction and pay fees for the transaction. When the EVM executes a transaction, the gas will gradually run out according to specific rules.

** Gas price ** is a value set by the sender of the transaction, and the sender’s account requires a prepaid fee = gas_price * gas. If there is any left after the transaction is executed, the gas will be returned the same way.

No matter where the execution goes, once the gas is exhausted (such as falling to a negative value), an out-of-gas exception will be triggered. All state changes made in the current call frame will be rolled back.

Then there may be a problem. If the gas price is set by the transaction sender himself, isn’t it the lower the better the money? Everyone doesn’t want to pay more. To solve this problem, we must first deal with three concepts:

Gas

Gas corresponds to the actual number of steps of the Ethereum Virtual Machine (EVM) in a transaction. The simpler the transaction, such as a simple

For Ether transfer transactions, the fewer steps required, the less Gas will be required. Conversely, if you want to calculate some complex operations, the consumption of Gas

The volume will be large. So the larger the amount of computation required by the EVM for the transaction you submit, the higher the required Gas consumption.

Gas Price

Gas Price is how much Eth you are willing to pay for a unit of Gas, usually in Gwei. So the higher the Gas Price,

This means that for each calculation step in the transaction, more Eth will be paid.

You may be unfamiliar with the unit Gwei. Gwei is actually 10 ^ -9 Eth, which means 1 Gwei = 0.000000001 Eth.

So, when you set Gas price = 20 Gwei, it means that you are willing to pay 0.00000002 Eth for a single step.

At this point, if you are smart, you will realize that the formula for calculating Ethereum’s fees is very simple:

Transaction Fee (Tx Fee) = Actual Gas Used * Single Step Price (Gas Price)

For example, your transaction requires Ethereum to perform 50 steps to complete the operation. Suppose the Gas Price you set is 2 Gwei, then the transaction fee

50 * 2 = 100 Gwei.

Gas Limit

Gas Limit is the upper limit of gas available in a transaction, which is the maximum number of operations that will be executed in your transaction. Due to the different complexity of transactions,

The exact gas consumption will not be known until the transaction is completed, so you need to set a gas consumption limit for the transaction before you submit it.

If the transaction you submitted has not been completed and the gas consumed has exceeded the gas limit you set, then the transaction will be cancelled

Fees that have already been consumed are also deducted - because miners who have already worked are rewarded. And if the transaction has been completed and the gas consumed has not reached the Gas Limit,

Then only the transaction service fee will be charged based on the actual gas consumed. In other words, the highest service fee that a transaction may be charged is Gas Limit * Gas Price.

Finally, it is worth mentioning that the higher the Gas Price, the faster your submitted trades will be accepted by miners. But usually people are reluctant to pay more fees

** Delegate calls/code calls and libraries **

There is a special type of message call called delegatecall. It differs from ordinary message calls in that the code at the target address will be executed in the context of the calling contract, and msg.sender and msg.value remain unchanged. This means that a contract can dynamically load code from another address at runtime. The store, current address, and balance all point to the calling contract, only the code is retrieved from the called address. This allows Solidity to implement “library” capabilities: reusable code libraries can be placed on a contract store, such as libraries used to implement complex data structures.

** Journal **

There is a special indexable data structure that stores data that can be mapped all the way up to the block level. This feature is called logs and is used by Solidity to implement events. The log data cannot be accessed after the contract is created, but it can be efficiently accessed from outside the blockchain. Because part of the log data is stored in 布隆过滤器(Bloom filter) We can search logs efficiently and cryptographically securely, so network nodes (light clients) that have not downloaded the entire blockchain can also find these logs.

** Create **

Contracts can even create other contracts through a special instruction (not simply calling zero address). The only difference between calls to create contracts ** create calls ** and ordinary message calls is that the payload will be executed, the result of execution is stored as contract code, and the caller/creator gets the address of the new contract on the stack.

** Self-destruct **

The only way to remove contract code from the blockchain is to self-destruct the contract at the contract address. The remaining ether on the contract account will be sent to the specified target, and then its storage and code will be removed from the state.

Key concepts explained again

** Account **

Ethereum introduced the concept of accounts to replace the Bitcoin UTXO model. There are two types of accounts in Ethereum, external accounts and contract accounts, and there is no difference between the two types of accounts for EVM. Each account has an account state associated with it and a 20-byte address, both of which can store Ether.

External account: Controlled by private key, no code is associated with it, and the address is determined by public key. The private key can be used to sign transactions and actively initiate transactions to other accounts for message transmission.

Contract account: controlled by the contract code, associated with the code, and its address is determined by the address of the contract creator and the number of transactions nonce sent by the address. You cannot initiate transactions to other accounts, but you can “respond” to other accounts to make message calls.

Messaging between external accounts is the process of value transfer. Transactions from external accounts to contract accounts or messages from contract accounts to contract accounts will trigger the execution of contract account code, allowing it to perform various operations such as transferring tokens, writing to internal storage, performing operations, creating contracts, etc.

Account status

Regardless of the account type, the account status includes the following four fields:

Nonce: Random number, the sum of the number of transactions issued by the account and the number of contracts created.

Balance: Balance, the amount of ether in the account, the unit is Wei, 1Ether = 10 ^ 18Wei.

storageRoot: The hash encoding of the root node of the MerklePatricia tree that stores the root node, account content.

CodeHash: Code hash, the hash value of the EVM code associated with the account, the codeHash of the external account is a hash of an empty string, which cannot be changed after creation. The state database contains all code snippet hashes for subsequent use.

img

** Transaction **

External accounts send signed data packets to other accounts. Each transaction will change the state of Ethereum, will be serialized, and will be recorded in the blockchain after being verified and broadcast by miners. Therefore, transactions are asynchronous, and the only value that can be returned immediately is transaction hash. Transactions can be divided into creating contracts and passing messages. The completion of a transaction may require triggering multiple messages and message calls.

The transaction includes:

∙ Recipients of transactions

∙ A signature that can identify the sender of the transaction and prove that it is a transaction sent by the sender to the recipient through blockchain

∙ VALUE, the amount of ether to be transferred (wei)

∙ Gas Limit (sometimes referred to as StartGas), the maximum amount of gas allowed to be consumed during transaction execution

∙ Gas Price, the price of a unit of gas specified by the transaction sender (in Ether)

** Message **

Data and values transferred between two accounts (Ether). It does not necessarily change the state of Ethereum. Virtual objects that only exist in the Ethereum execution environment will not be serialized or recorded in the blockchain. Messages are synchronized and return values can be obtained immediately.

Message call

The behavior of passing messages from one account to another is similar to Transaction, but virtual objects that only exist in the Ethereum execution environment will not be recorded in the blockchain. It can be analogous to function calls. If the target account is a contract account, the EVM code of the contract account is triggered for execution. If both accounts are contract accounts, the return values of all virtual machines can be passed in the call.

The message contains:

∙ The sender of the message (implicit)

∙ Recipients of messages

∙ VALUE, the amount of ether delivered to the contract address with the message (wei)

∙ Optional data fields as input to contracts

∙ STARTGAS, which limits the maximum amount of gas that can be consumed by code execution triggered by this message

Message invocation and message are usually synonymous, and there is no need to strictly distinguish them.

Transactions and messages do not contain a relationship, but partially overlap: the transaction sender directly sends the transaction to the specified address of Ethereum without going through the contract to create a contract. There is no process of message call, and it only belongs to the transaction; the transaction sender calls the contract from one The operation of transferring money to another account belongs to both transactions and message calls; the contract account is motivated by an external account to create a contract, which only belongs to message calls and not transactions.

Transactions must be initiated by external accounts. A transaction may trigger a series of “message calls”. The contract account “responds” to “message calls” from other accounts and the executable code then triggers new “message calls”. Therefore, in essence, all “message calls” and state changes of Ethereum are triggered by external accounts. That is, Ethereum can be seen as a transaction-based Finite-State Machine as a whole: starting with a Genesis state, and then gradually changing as the transaction executes until the final state, which is the authoritative version of the Ethereum world.

Off topic

All-zero address

There is an address in Ethereum that has a lot of ether, and this address is an all-zero address, so why does this address have so many ether?

This starts with the genesis block of Ethereum.

The main source of ETH is not mining, but published during crowd funding.

Even today, nearly three years after Ethereum’s official release, the 72 million ETH published in the genesis block still accounts for 73.4%.

So, is the ETH in this all-zero address from the ETH published in the genesis block?

Actually it’s not.

However, by analyzing the genesis block, it can be found that the miner who dug out the genesis block was actually this all-zero address.

The genesis block was not mined, it was artificially created and used as the starting point for the entire blockchain.

Since it was not dug out, it is reasonable to use all-zero addresses as placeholders.

Because the genesis block is not mining income, no one consumes computing power for it, and naturally there will be no block reward.

After turning around, the ETH in this all-zero address has nothing to do with the genesis block.

In addition to the ETH published in the genesis block, there is only one way to generate new ETH, which is mining.

For more accurate calculation, the following units use the smallest unit Wei of ETH. For unit issues, you can refer to here "以太币(Ether)的单位》。

Search for the block where the miner is this all-zero address, there are quite a few.

This all-zero address has mined a total of 94 main chain blocks.

So the question is, why do some people use all-zero addresses to mine, so that they consume electricity, but ultimately benefit from all-zero addresses.

The earliest block mined with an all-zero address is 5305, with a difficulty value of only 199,485,740,316, less than 0.2T, or a 1060 graphics card, for example, it takes less than 3 hours to find a block.

Back then, blocks were so easy to mine that almost any mid-range PC with a discrete graphics card could mine blocks.

As a result, many people try to use their own ordinary PC to try mining, almost 0 cost.

Among this group of people, a considerable part of them were newbies who could only copy and paste. The sad thing was that they forgot to set the payment address. Some professional miners also did not configure the mining software for convenience when debugging the stability of the machine.

When solo mining, some wallet software will use all-zero address mining by default if the payment address is not set.

** This also explains why so many blocks are mined with all-zero addresses. **

And it should be noted that the all-zero address is a black hole address. No one has the private key of the all-zero address in their hands, and we cannot reverse calculate the private key of the all-zero address through all zeros, so in theory, The ether that entered the black hole address can no longer be transferred out.

How smart contracts work

Bitcoin transactions are very simple. You can do just one thing. One type of transaction. Skipping a few details, everything boils down to ** TO (who is paying, who is receiving money), FROM (from, who is paying), and AMOUNT ** (quantity, how much money). This makes Bitcoin a store of value, capable of transferring value between network participants.

The difference in Ethereum is that transactions also have a “** DATA” ** (data) field. This “** DATA **” field supports three types of transactions:

** Value transfer (same as Bitcoin) **

** TO ** receiving address;
The DATA field is empty or contains any messages to be appended;

  • ** FROM ** you
  • ** AMOUNT is ** the amount of Ethereum you want to send

** Create a smart contract **

  • TO field is empty (it triggers the creation of smart contract)
  • The DATA field contains smart contract code compiled into byte code (so in fact the code we write is used to create contract code, not the actual contract code stored on the chain).
  • FROM YOU
  • AMOUNT can be 0 or any amount of ether you want to put in the contract

** Call smart contract **

  • TO field is the smart contract account address
  • DATA field contains function name and parameters - how to call smart contract
  • FROM YOU
  • AMOUNT can be 0 or any amount of ether, such as the amount you need to pay for a service contract

Contracts and Contract Accounts

The contract is a collection of code and the current state of the account. After each transaction, the current contract will

Reference article:

https://blog.csdn.net/sportshark/article/details/52249607

https://solidity-cn.readthedocs.io/zh/develop/solidity-by-example.html

https://learnblockchain.cn/2018/01/04/understanding-smart-contracts/

https://blog.csdn.net/jiang_xinxing/article/details/80289694

https://zhuanlan.zhihu.com/p/34363341

https://www.chainnews.com/articles/891681682372.htm