What is a smart contract

Introduction to Smart Contracts

A simple smart contract

Let's start with a very basic example, don't worry you don't understand it at all, we will gradually learn more details.

Storage

contract SimpleStorage {
    uint storedData;

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

    function get() constant returns (uint retVal) {
        return storedData;
    }
}

In Solidity, a contract consists of a set of code (the function of the contract) and data (the state of the contract). The contract is located at a special address on the Ethereum blockchain. *uint storedData* ;  This line of code declares a state variable named storedData of type  uint  (256bits unsigned integer). You can think of it as a storage unit in the database, just like the management database, you can query and modify it by calling functions. In Ethereum, usually only the owner of the contract can do this. In this example, the functions  set  and  get  are used to modify and query the value of a variable, respectively.

As in many other languages, there is no need to add a prefix like this. to access state variables.

This contract can't do much yet (limited by Ethereum's infrastructure), just allow anyone to store a number. And anyone in the world can access the number, lacking a (reliable) way to protect the numbers you publish. Anyone can call the set method to set a different number over the number you posted. But your numbers will remain in the history of the blockchain. Later we will learn how to add an access limit so that only you can change this number.

Token example

The next contract will implement a cryptocurrency in its simplest form. Air withdrawal is no longer a magic trick, of course only the person who created the contract can do this (it is also very simple to issue other currency models, just the difference in implementation details). And anyone can send money to other people without registering a user name and password, as long as they have a pair of Ethereum public and private keys.

Note

This is not a good example for an online solidity environment. If you use the online solidity environment  to try this example. When the function is called, the address of from cannot be changed. So you can only play the role of the mint, you can mint money and send it to other people, but you can't play the role of other people. This online solidity environment will be improved in the future.

contract Coin {
//关键字“public”使变量能从合约外部访问。
    address public minter;
    mapping (address => uint) public balances;

//事件让轻客户端能高效的对变化做出反应。
    event Sent(address from, address to, uint amount);

//这个构造函数的代码仅仅只在合约创建的时候被运行。
    function Coin() {
        minter = msg.sender;
    }
    function mint(address receiver, uint amount) {
        if (msg.sender != minter) return;
        balances[receiver] += amount;
    }
    function send(address receiver, uint amount) {
        if (balances[msg.sender] < amount) return;
        balances[msg.sender] -= amount;
        balances[receiver] += amount;
        Sent(msg.sender, receiver, amount);
    }
}

This contract introduces some new concepts, let's take a look at them one by one.

address public minter; This line of code declares a publicly accessible state variable of type address. The value of type address has a size of 160 bits and does not support any arithmetic operations. Suitable for storing the contract's address or other people's public and private keys. The public keyword automatically generates access functions for its modified state variables. Variables without the public keyword will not be accessible by other contracts. In addition, only the code in this contract can be written. The automatically generated function is as follows:

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

Of course, it is not feasible for us to add such an access function ourselves. The compiler will complain that the function has the same name as a state variable.

The next line of code  mapping (address => uint) public balances; creates a public state variable, but its type is more complex. This type maps some address to an unsigned integer. Mapping can be thought of as a hash table, and the value corresponding to each possible key is virtually initialized to all 0s. This analogy is not very strict. For a mapping, it is impossible to obtain a linked list containing all its keys or values. So we have to remember what to add to the mapping. A better way is to maintain a linked list like this, or use some other higher-level data type. Or use mapping only in scenarios that are not affected by this flaw, like this example. In this example, the access function generated by the public keyword will be more complicated, and its code is roughly as follows:

function balances(address _account) returns (uint balance) {
    return balances[_account];
}

We can easily query the balance of a specific account through this function.

event Sent(address from, address to, uint value); This line of code declares an "event". Triggered by the last line of code in the send function. Clients (and server applications as well) can listen to these blockchain-triggered events with very little overhead. When the event is triggered, the listener will receive the from, to, value parameters at the same time, which can be easily used to track transactions. To listen for this event, you can use the following code:

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 how the auto-generated balances function is called in the client.

There is a special function Coin here. It is a constructor that runs when the contract is created and cannot be called afterwards. It will permanently store the address of the contract creator. msg (along with tx and block) is a magic global variable that contains some blockchain-specific properties that can be accessed by contract code. msg.sender always holds the address of the external caller of the current function.

Finally, the functions that are actually called by users or other contracts to complete the functions of this contract are mint and send. If someone other than the contract creator calls mint, nothing happens. And send can be called by anyone (with a certain amount of tokens) to send some coins to others. Note that when you send some tokens to an address via this contract, querying that address in a blockchain explorer will see nothing. Balance changes due to sending a token are only stored in the data store for that token contract. Through events we can easily create a "blockchain explorer" that can track your new currency transactions and balances.

Blockchain Basics

For programmers, the concept of blockchain is actually not difficult to understand. Because some of the hardest things to understand (mining, hashing, elliptic curve encryption, peer-to-peer networking, etc.) are just to provide a set of features and guarantees. You just need to accept these existing features and don't need to care about the underlying technology. Just like if you just use Amazon's AWS, you don't need to understand its inner workings.

transaction/transaction

A blockchain is a globally shared, transactional database. This means that everyone participating in the network can read the records in it. If you want to modify something in this database, you have to create a transaction and get confirmation from everyone else. The word transaction means that the modification you want to make (if you want to modify two values ​​at the same time) can only be implemented completely or not at all.

Also, when your transaction is applied to this database, other transactions cannot modify the database.

As an example, imagine a table that lists the balances of all accounts of a certain electronic currency. When a transfer request occurs from one account to another, the transactional nature of this database ensures that the amount deducted from one account is added to the other. If, for some reason, adding an amount to the target account is not possible, the amount in the source account will not change.

Additionally, a transaction is cryptographically signed by the sender (creator). This measure intuitively adds access protection to specific modifications to the database. In the case of electronic money, a simple check can ensure that only the person who holds the account key can transfer money out of the account.

block

One of the major conundrums to be solved by the blockchain is known in Bitcoin as a "double-spend attack". What happens when two transactions appear on the network that both use up the money in one account? a conflict?

The simple answer is that you don't need to care about this. These transactions are ordered and packaged into "blocks", which are then executed and distributed by all participating nodes. If two transactions conflict with each other, the transaction in the lower order will be rejected and removed from the block.

The blocks are arranged in a linear sequence in time. This is where the term "blockchain" comes from. Blocks are added to the chain at fairly regular intervals. For Ethereum, this interval is roughly 17 seconds.

A segment of the blockchain may be rolled back from time to time as part of an "order selection mechanism" (often called "mining"). But this only happens at the end of the entire chain. The more blocks involved in a rollback, the less likely it will happen. So your transaction may be rolled back or even deleted from the blockchain. But the longer you wait, the less likely this will happen.

Ethereum Virtual Machine

Overview

The Ethereum Virtual Machine (EVM) is the runtime environment for smart contracts in Ethereum. Not only is it sandboxed, it is in fact completely isolated, which means that code running inside the EVM cannot touch the network, file system, or other processes. Even smart contracts have limited contact with other smart contracts.

account

There are two types of accounts in Ethereum that share the same address space. External accounts, which are controlled by public-private key pairs (humans). Contract accounts, which are controlled by the code stored in the account.

The address of the external account is determined by the public key, and the address of the contract account is determined when the contract is created (this address is calculated from the address of the contract creator and the number of transactions sent by the address, and the number of transactions sent by the address is also called "nonce")

Except for the fact that contract accounts store code, external accounts do not, these two types of accounts are the same to EVM.

Each account has a persistent store in the form of key-value. The length of key and value are both 256 bits, and the name is storage.

Additionally, each account has an ether balance (in "Wei") that can be changed by sending it a transaction with ether.

trade

A transaction is a message sent from one account to another (possibly the same account or zero account, see below). Transactions can contain binary data (payload) and ether.

If the target account contains code, that code will execute, and the payload is the input data.

If the target account is a zero account (the account address is 0), the transaction will create a new contract. As mentioned above, this contract address is not a zero address, but is calculated from the contract creator's address and the number of transactions (called a nonce) sent by that address. The payload that creates the contract transaction is executed as EVM bytecode. The output of the execution is permanently stored as contract code. This means that in order to create a contract, you don't need to send the actual contract code to the contract, but code that returns the real code.

Gas

Every transaction on Ethereum is charged a certain amount of gas, and the purpose of gas is to limit the amount of work required to execute a transaction, while paying a fee for execution. When the EVM executes a transaction, gas will be gradually consumed according to certain rules.

The gas price (in ether) is set by the transaction creator, and the sending account needs to prepay the transaction fee = gas price * gas amount. If there is gas remaining at the end of the execution, the gas will be returned to the sending account.

No matter where the execution is, once the gas is exhausted (for example, it falls to a negative value), an out-of-gas exception will be triggered. All state modifications made by the current calling frame will be rolled back.

storage, main memory and stack

Each account has an area of ​​persistent memory called storage. Its form is key-value, and the length of both key and value is 256 bits. In the contract, the storage of the account cannot be traversed. Compared with the other two, the storage read operation is relatively expensive, and the modification storage is even more expensive. A contract can only read and write to its own storage.

The second memory area is called main memory. Every time the contract executes a message call, there is a new, cleared piece of main memory. Main memory can be addressed at byte granularity, but read and write granularity is 32 bytes (256 bits). The overhead of operating main memory grows (square level) as it grows.

EVM is not a register based, but a stack based virtual machine. So all computations are performed in an area called the stack. The stack has a maximum of 1024 elements of 256 bits per element. Access to the stack is limited to its top by allowing one of the top 16 elements to be copied to the top of the stack, or to swap the top element with one of the 16 elements below. All other operations take only the top two (or one, or more, depending on the operation) elements and push the result on top of the stack. Of course you can put elements on the stack into storage or main memory. However, it is not possible to access only the element at the specified depth on the stack. Before that, all elements above the specified depth must be removed from the stack.

Instruction Set

The instruction set of the EVM is deliberately kept to a minimum size to avoid buggy implementations that could lead to consensus issues as much as possible. All instructions operate on the basic data type of 256 bits. Equipped with common arithmetic, bit, logic and comparison operations. Conditional and unconditional jumps are also possible. Additionally, the contract has access to relevant properties of the current block, such as its number and timestamp.

message call

Contracts can call other contracts or send ether to non-contract accounts through message calls. Message calls and transactions are very similar in that they both have a source, a destination, data payload, ether, gas and return data. In fact each transaction can be thought of as a top-level message call, which in turn spawns more message calls.

A contract can decide the allocation of remaining gas. Such as how much gas is used for internal message calls, or how much gas is expected to be reserved. If an out-of-gas exception (or other exception) occurs during the internal message call, the contract will be notified and an error code will be pushed on the stack. This situation is just gas running out of internal message calls. In solidity, the contract making the call in this case triggers an artificial exception by default. This exception will print out the call stack. As said before, the called contract (and the calling contract as well) will have fresh main memory and be able to access the calling payload. The call payload is stored in a separate area called calldata. After the call is executed, the returned data will be stored in a block of memory pre-allocated by the caller.

Call levels are limited to 1024, so for more complex operations we should use loops instead of recursion.

Code Calls and Libraries

There is a special type of message call, called callcode. It is almost identical to a message call, except that the code loaded from the target address will run in the context of the contract that made the call.

This means that a contract can dynamically load code from another address at runtime. Storage, current address and balance all point to the calling contract, only the code is fetched from the called address.

This enables Solidity to implement "libraries". Reusable library code can be applied to the storage of a contract and can be used to implement complex data structures.

log

At the block level, a special indexable data structure can be used to store data. This feature is called logging, and Solidity uses it to implement events. Log data cannot be accessed after the contract is created, but this data can be efficiently accessed from outside the blockchain. Because part of the log data is stored in a Bloom filter, we can search logs efficiently and safely, so those logs can also be found by network nodes (light clients) that do not download the entire blockchain.

create

Contracts can even create other contracts with a special instruction (not simply making a call to address zero). The difference between a call to create a contract and an ordinary message call is that the result of the payload data execution is treated as code, and the caller/creator gets the address of the new contract on the stack.

self-destruct

The contract code is only removed from the blockchain when the contract at an address performs a self-destructing operation. The remaining ether on the contract address is sent to the designated destination, and its storage and code are removed.

Note that even if the code of a contract does not contain a self-destruct instruction, it can still be executed by calling code (callcode).

-----------------------------------------------------------------------------------------------------

If you want to learn Ethereum DApp development efficiently , you can visit the most popular online interactive tutorials provided by Huizhi.com:

1.  An introductory tutorial on Ethereum DApp smart contracts
for newcomers to blockchain 2.  Blockchain +IPFS+Node. js+MongoDB+Express decentralized Ethereum e-commerce application development practice

3. Other more content can also visit this Ethereum blog .

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325950579&siteId=291194637