V God's design concept announced, detailing the potential advantages and disadvantages of Ethereum
herehere, this reprint has been proofread. I would like to express my gratitude to the original translator Kim.
The writing time of the original text is uncertain, but it can be regarded as a starting point to reflect on the design concept of Ethereum and the evolution of Ethereum in the past few years. It is not only to reflect on its innovation, but also to reflect on its lack of consideration.
in principle
in principle
The design of the Ethereum protocol follows the following principles:
Sandwich Complex Model (also translated as "complexity layered model"): We believe that the underlying protocol of Ethereum should be as simple as possible, and the interface design should be easy to understand (whether it is a developer-oriented high-level programming language interface or a user-oriented use interface). Those unavoidable complex parts should be placed in the middle layer. The middle layer is not part of the core consensus and is invisible to end users. It includes: high-level language compilers, parameter serialization and deserialization scripts, storage data structure models, leveldb storage interfaces, and networking protocols. Of course, the line of distinction is not absolutely clear, and sometimes needs to be adjusted as appropriate.
Freedom: Users should not be restricted from using the Ethereum protocol, nor should they try to favor or not support certain Ethereum contracts or transactions. This is similar to the guiding principles behind the concept of "net neutrality". The Bitcoin transaction protocol does not follow this principle: the Bitcoin transaction protocol does not encourage "off-labal purposes" (eg, data storage, meta-protocols) of the blockchain (proofreading note: off-labal's The original intention is to use the drug for symptoms other than its approved indication, such as the use of cough medicine to treat headaches. Here, it is paraphrased as "unconventional use" ); and, sometimes, some people use quasi-protocol layer changes (e.g. limit the length of the OP_RETURN field to 40 bytes) to attack applications that use the blockchain in an "unauthorized" way Propensity). Therefore, in Ethereum, we firmly support the method of using only transaction fees to achieve roughly incentive compatibility-the more resources users consume in the entire network, the higher the price they need to pay, even if they bear the cost themselves (ie Pigou Tax).
Generalization: The properties and opcodes of the Ethereum protocol should maximize low-level concepts (like elementary particles), so that they can be combined at will, including combining things that seem useless today, but may be useful in the future. Also, low-level concepts can be made more efficient by stripping away unneeded functionality. An example of following this principle is our choice of the LOG opcode as the way to provide information to the dapp, rather than logging all transactions and messages as before. In the early days, the concept of "message (message)" was completely a collection of various concepts, which included "function call (function call)" and "event information (event) of interest to external observers", and the two are completely separable.
No feature is the biggest feature: In order to follow the principle of generalization, we refuse to embed those advanced use cases as part of the protocol, even for frequently used use cases, we will never do so. If one really wants to implement these use cases, sub-protocols can be created within the contract (eg, Ethereum-based sub-currency, Bitcoin/Litecoin/Dogecoin sidechains, etc.). For example, Ethereum lacks the "time lock" function similar to Bitcoin. However, this function can be simulated through the following protocol: the user sends a signed data packet to a specific contract for processing, and if the data packet is valid in the specific contract, the corresponding function is executed.
Not risk-averse: We are willing to take higher risks if the increased risk brings measurable benefits (eg, common state transitions, 50x reduction in block time, consensus efficiency, etc.).
first level title
Blockchain Layer Protocol
secondary title
account, not UTXO 1
Bitcoin and its many variants store the user's balance information in the UTXO structure, and the entire state of the system consists of a series of "unspent outputs" (you can think of these "unspent outputs" as coins) (proofreading Note: A better metaphor might be "cheque".). Each UTXO has an owner and its own value attributes. A transaction will generate several new UTXOs while consuming several UTXOs; and the transaction is subject to the following validity requirements:
1. Each referenced input must be valid and unused; 2. The signature of the transaction must match the signature of the owner of each input; 3. The total value of the input must be equal to or greater than the total value of the output.
image description
- Triple-entry bookkeeping used by Bitcoin -
However, Ethereum abandoned the UTXO scheme and turned to a simpler method: using the concept of state (state) to store a series of accounts, each account has its own balance, and Ethereum-specific data (code and internal memory ). If the account balance of the transaction initiator is sufficient to cover the transaction fee, the transaction is valid, and the corresponding amount will be deducted from the initiator's account and credited to the receiving account. In some cases, if there is code that needs to be executed in the receiving account, the transaction will trigger the execution of the code, then the internal memory of the account may change, and may even create additional messages to be sent to other accounts, resulting in new transactions occur.
Although Ethereum does not adopt the concept of UTXO, UTXO has some advantages:
Higher degree of privacy protection:If a user uses a new address for every transaction, interlinking accounts is difficult. This is suitable for currency systems with high security requirements, but not suitable for any dapp. Because dapps usually need to track the complex binding state of users, and the state of dapps cannot be divided as simply as the state in the currency system.
Potential scalability:In theory, UTXO is more suitable for certain types of scalability schemes (scalability paradigm), because only the holders need to have a Merkel proof that can prove their currency ownership, even if everyone (including TA himself) This data is forgotten, and this person is really damaged, and others are not affected. In the Ethereum account system, if everyone loses the part of the Merkle tree corresponding to an account, then the account will not be able to process any messages that can affect it, including messages sent to it, and it will not be able to process it. However, UTXO is not the only one that can be expanded, and there are ways to expand without relying on UTXO (there is no expansion here, Translator's Note).
Save a lot of space: If an account has 5 UTXOs, then the required space will be reduced from 300 bytes to 30 bytes when switching from UTXO mode to account mode. The specific calculation is as follows: 300 = (20+32+8) * 5 (20 is the number of address bytes, 32 is the number of TX id bytes, and 8 is the number of bytes occupied by the denomination); 30 = 20 + 8 + 2 ( 20 is address bytes, 8 is account balance value bytes, 2 is nonce 2 bytes); but the actual saving is not that big, because accounts need to be stored in the Patricia tree. In addition, transactions in Ethereum are smaller than those in Bitcoin (100 bytes in Ethereum, 200-250 bytes in Bitcoin), because each transaction only needs to generate one reference, one signature, and one output.
Stronger interchangeability: The UTXO structure does not have the concept of a blockchain layer, so whether it is technically or legally, establishing a red list/black list and distinguishing them based on the source of these "valid outputs" is not very practical.
Simplicity: Ethereum coding is simpler and easier to understand, especially when complex scripts are involved. Although any decentralized application can be (reluctantly) implemented with UTXO, this method essentially empowers the script to limit the types of UTXO that a given UTXO can output and its usage conditions (for example, it needs to contain Merkle tree Proof to help the script's corresponding application change the state root). Therefore, UTXO implementation is much more complicated than the way Ethereum uses accounts.
Light Client: A light client can access all data related to an account at any time by scanning the state tree in a specified direction. In the UTXO paradigm, each transaction needs to use different references, which is undoubtedly heavy for long-running dapp applications that use the UTXO root state propagation mechanism mentioned above.
The benefits of the account are as follows:
We believe that the benefits of accounts greatly outweigh the alternatives, especially for the kind of dapps we want to support that can contain arbitrary state and code. In addition, in line with the guiding principle of "no feature is the biggest feature", we believe that if users really care about privacy, they can build an encrypted "mixer and coinjoin" through the signed data packet protocol in the contract Obfuscate payment paths.
A weakness of the account method is that in order to prevent replay attacks (replay attacks, which means that the same transaction is executed repeatedly), each transaction must have a "nonce" (serial number). Therefore, each account must have a nonce value that is updated in real time, and each new transaction increments the account nonce value by 1 as its own nonce (and updates the account's nonce value by this value after transaction processing) (proofreading note : In the account mode, if the transaction does not have this consumable identifier attached, the transaction can be processed repeatedly, so that the receiving account can collect the account over and over again without paying any cost, while the sending account will be sucked dry ; the nonce of the Ethereum account is incremented as the initiated transaction is processed, which solves this problem). This means that even accounts that are no longer in use cannot be removed from the account status. A simple solution to this problem is to have transactions contain a block number, making them irretrievable after a certain period of time, and reset the nonce every so often.
If you want to delete an account in the state (such as an account that has not been used for a long time), you must first "ping" them out, and the overhead of fully scanning the blockchain protocol is very large. We did not implement this mechanism on 1.0, and versions 1.1 and above may use this mechanism.
Proofreading Note: This is the technical reason for the "state explosion" problem that Ethereum will face in the future: all state data must be completely preserved, and accounts cannot be deleted reasonably. As a blockchain protocol, the nodes of Ethereum must not only reach a consensus on the order of transactions (transactions), but also reach a consensus on the global state (the form of expression is that the state root needs to be included in the block header. Therefore, to delete the state, It also requires the consensus of the entire network, otherwise it will fall into division.
This articleThis article。
Merkel Patricia Tree (MPT)
Merkle Patricia tree/trie, conceived by Alan Reiner and implemented in the Ripple protocol, is the main data structure of Ethereum, used to store all account states, and each block Transaction and receipt data in . MPT is a combination of Merkle tree and Patricia tree, and the structure created by combining these two trees has the following properties:
The root hash value corresponding to any set of key-value pairs is unique. If you want to falsely claim that a key-value pair exists on a certain tree, it will definitely be seen through (unless the attacker has about 2^128 computing power).
The time complexity of adding, deleting, and changing a key-value pair is logarithmic.
There are two types of nodes: KV nodes and discrete nodes. The presence of KV nodes improves efficiency, because if the tree is sparse in a certain region, KV nodes can be used as a "shortcut" to compress the height of the tree (read the detailed description of MPT for more details).
Discrete nodes are hexadecimal, not binary: this makes lookup more efficient, a choice we now realize is not ideal, since the lookup efficiency of a hex tree can be simulated in binary by storing nodes in batches. However, the implementation of the MPT tree structure is very error-prone and ends up causing at least a mismatch in the state root, so we decided to put the change on hold until 1.1.
There is no distinction between empty value and non-membership: this is done to simplify the logic, the value (balance) of an account that is not enabled in Ethereum defaults to 0, and the empty string is also represented by 0. However, it should be emphasized that this sacrifices some generality and is therefore not optimal.
The difference between terminating and non-terminal nodes: Technically, it is unnecessary to identify a node "whether it is a terminal node" because all trees in Ethereum are used to store fixed-length (ie, key length) data, but in order to increase versatility, we will still add this logo, hoping that the implementation of Ethereum's MPT can be adopted by other cryptocurrencies as they are.
Use SHA3(k) as a key in the "security tree" (state tree and account storage tree): using SHA3(k), you want to generate many accounts (accounts can make the state tree up to 64 levels!) and repeatedly call The SLOAD and SSTORE opcodes make DoS attacks much more difficult. Note that this also makes it harder to enumerate the tree; if you want your client to be able to enumerate, the easiest way is to maintain a database mapping sha3(k) -> k.
MPT provides us with an efficient, easy-to-update "fingerprint" that represents the entire state tree. A more detailed description of MPT: https://github.com/ethereum/wiki/wiki/Patricia-Tree.
The specific design decisions for the MPT are as follows:
Proofreading Note: The meaning here is that if k is used as the key of the Merkle tree to store data, its distribution may be very sparse, and an attacker can easily plan accounts that require a deep tree path to store, and target these accounts Repeatedly calling the state access operation causes overloading of the nodes in the network. However, the result of the hash function is randomly distributed. Using sha3(k) as the key can make the key distribution more uniform and the tree height will be shorter ).
This feature also has advantages and disadvantages. On the one hand, it means that DoS attacks will become more difficult. On the other hand, it also makes the state tree access paths of transactions in a block rarely overlap, so each search Both are the worst case complexity.
In addition, this also makes it unsuitable for MPT to achieve "statelessness" (the block itself carries the data required for verification, and the verifier does not need to have a global state), because the paths of state access do not overlap, and the space efficiency of the evidence is also the worst case. Of course, it can also be said that the space efficiency of the Merkle tree evidence itself is not high enough
RLP
RLP (recursive length prefix): Recursive length prefix.
RLP encoding is the primary serialization format in Ethereum, and it is used everywhere: blocks, transactions, account states, and network protocol messages. See the official description of RLP for details: https://github.com/ethereum/wiki/wiki/RLP
RLP is intended to be a highly simplified serialization format whose sole purpose is to store nested byte arrays3. Unlike existing solutions such as protobuf and BSON, RLP does not define any specific data types such as Boolean (Boolean), float (floating point), double or integer (integer). It just stores structures in the form of nested arrays, and it is up to the protocol to determine the meaning of the array. RLP also does not explicitly support map collections. The semi-official suggestion is to use a nested array of [[k1, v1], [k2, v2], ...] to represent the key-value pair collection, k1, k2 ... according to Standard sorting for strings.
A scheme that has the same function as RLP is protobuf or BSON, which are algorithms that have been used all the time. However, in Ethereum, we prefer to use RLP because: (1) it is easy to implement; (2) byte consistency is absolutely guaranteed.
Many languages don't have an explicit ordering of key-value pairs collections, and floating-point formats have many special cases that can result in different encodings and different hashes for the same data. By developing the protocol internally, we can ensure that it is designed with these goals in mind (this is a general principle that also applies to other parts of the code, such as the virtual machine). The encoding method used by BitTorrent, bencode, may be an alternative to RLP. However, it uses a decimal encoding method, which is slightly inferior to the binary RLP.
compression algorithm
Both network protocols and databases use a custom compression algorithm to store data. The algorithm can be described as: use run-length encoding 4 for 0 while preserving other values (except some special cases such as sha3(' ') ), for example:
Before the compression algorithm existed, there were some special cases in many places in the Ethereum protocol. For example, sha3 was often redefined so that sha3(' ')=' ', so that there is no need to store code in the account, which can save 64 bytes. Recently, however, all of these special cases that made Ethereum's data structures bloated have been removed, and instead data preservation functions have been added to layers outside of the blockchain protocol, i.e., into the network protocol and into its Insert user database implementation. This increases the modularization capability, simplifies the consensus layer, and makes the continuous update of the compression algorithm relatively simple to deploy (for example, it can be distinguished and deployed by the version number of the network protocol).
The use of the tree (trie)
Reminder: Understanding this part of the knowledge requires the reader to understand the principle of Bloom filter 5. The introduction can be seen at: http://en.wikipedia.org/wiki/Bloom_filter
Each block header in the Ethereum blockchain contains pointers to three trees: the state tree, the transaction tree, and the receipt tree.
The state tree represents the entire state after processing the block;
The transaction tree represents all transactions in the block, and these transactions are indexed by index as the key; (for example, k0: the first executed transaction, k1: the second executed transaction)
The receipt tree represents the corresponding receipt for each transaction.
in:
medstate: After the transaction is processed, the root of the state tree;
gas_used: the amount of gas used after the transaction is processed;
logs: is a list of many [address, [topic1, topic2...], data] elements. These elements are generated by opcodes LOG0 ... LOG4 called during transaction execution (contains the main call and subcalls); address is the address of the contract generating the log; topics is up to four 32-byte values; data is a word of any size section array;
logbloom: Bloom filter composed of addresses and topics of all logs in the transaction.
UTXO: unspent transaction outputs, literally: unspent transaction outputs, that is, transaction outputs that are not referenced by any transaction as an input. It is a data structure used in the Bitcoin protocol to store value (ownership) information. —— proofreading note
Nonce, the abbreviation of Number used once or Number once, in cryptography, Nonce is an arbitrary or non-repeating random value that is used only once, and both the initial vector and the encrypted hash function in encryption technology play an important role. In the communication application of various authentication protocols, it is ensured that authentication information is not reused to combat replay attacks (Replay Attack). ——Translator's Note
Nested arrays: Create an array and populate it with other arrays. Such as the array pets:
var cats : String[] = ["Cat","Beansprout", "Pumpkin", "Max"];
var dogs : String[] = ["Dog","Oly","Sib"];
var pets : String = [cats, dogs];——Translator's Note
run-length-encoding: A statistical encoding. The main technique is to detect repeated sequences of bits or characters and replace them with their number of occurrences. (Baidu Encyclopedia) - Translator's Note
first level title
in:
Notes:
Notes:
Rewards for uncle blocks
The GHOST protocol is a remarkable innovation first proposed in October 2013 by Yonatan Sompolinsky and Aviv Zohar. It is the first serious attempt to solve the problem associated with fast block generation.
The intention of GHOST is to solve such a problem: shorter block time (and thus faster confirmation speed) will lead to more blocks being "obsolete" and therefore less secure - because it takes time for blocks to propagate in the network , if miner A digs a block and broadcasts it to the whole network, and on the way of broadcasting, B also digs out the block, then B’s block is outdated, and B’s current mining does not contribute to the security of the network .
In addition, there is a centralization problem: if A is a mining pool with 30% of the computing power, B has 10% of the computing power. A has 70% of the time to generate outdated blocks (because the other 30% of the time will generate the latest block, it can be considered that TA "immediately" got the data of the latest block without waiting for block transmission), while B has 90% of the time Time to generate obsolete blocks. If the time interval between block production is very short, the obsolescence rate will become higher, and A will make mining more efficient with its greater computing power. Therefore, if blocks are generated too quickly, it will easily lead to the de facto monopoly of mining pools with large network computing power.
According to Sompolinsky and Zohar, GHOST solves the problem of network security degradation caused by outdated blocks in the process of calculating which chain is the longest chain. That is, not only the parent block and earlier blocks, but also obsolete collateral blocks (in Ethereum, we call them "uncle blocks") are also added to calculate which block has the largest total work Go to the proof.
In order to solve the second problem: the centralization problem, we adopted another strategy: block rewards are also provided for obsolete blocks: the reward for mining outdated blocks is 7/8 of the basic reward of the block; Nephew blocks of time blocks will receive 1/32 of the base reward as a bounty. However, transaction fees are not awarded to uncle and nephew blocks.
In Ethereum, obsolete blocks can only be included as uncle blocks by direct descendant blocks within 7 generations of their brother blocks. The reason for this limitation is that, first of all, if the GHOST protocol does not limit the intergenerational distance of obsolete blocks, it will spend a lot of overhead on calculating the validity of obsolete blocks; secondly, the unlimited incentive policy for obsolete blocks will make miners Loss of enthusiasm for mining on the main chain; in the end, calculations show that the obsolete block reward policy limited to layer 7 provides most of the desired effect without negative side effects.
A simulator for measuring centralization risk can be found here: https://github.com/ethereum/economic-modeling/blob/master/ghost.py
A higher level discussion can be found here: https://blog.ethereum.org/2014/07/11/toward-a-12-second-block-time/
Block time 12s: 12 seconds is chosen because this is already longer than the minimum time interval of network delay. In a 2013 paper on measuring the latency of the Bitcoin network, it was determined that 12.6 seconds was the time for a newly generated block to propagate to 95% of nodes; however, the paper also stated that the propagation time is proportional to the block size, so In faster currencies, we can expect propagation times to be greatly reduced. The propagation interval is constant at about 2 seconds. However, to be on the safe side, in our analysis we assume that the propagation of the block takes 12 seconds
Restriction within 7 generations of ancestors: The purpose of this design is to keep only a small number of blocks and clear the earlier blocks. A quotable range of 7 generations has been shown to provide most of the desired effects.
1-generation descendant restriction: (e.g. c(c(p(p(p(p(head))))) is invalid if c = child and p = parent): This is also a design goal for simplicity, And the aforementioned simulators show that this does not pose a significant centralization risk. (Proofreading Note: This sentence is difficult to understand; one possible meaning is: the descendants of the uncle block cannot be used as the uncle block, that is, only the generation of side branches of the main chain can be used as the uncle block.)
Uncle blocks must be valid: Uncle blocks must be valid headers, not valid blocks. This is also done for simplicity, keeping the blockchain model as a linear data structure (without turning into a DAG). However, it is also valid to require uncle blocks to be valid blocks.
first level title
Proofreading Note: The technical form of "include" here is: the nephew block references the block hash value of the uncle block in the block header, and then includes the block header of the uncle block in the block body.
Design decisions for the blocktime algorithm include:
Difficulty Update Algorithm
Currently, Ethereum performs difficulty updates through the following rules:
The design goals of the difficulty update rule are as follows:
Fast update: The time between blocks should be adjusted quickly with the increase or decrease of hash power;
Low volatility: if the mining power is constant, the difficulty should not fluctuate wildly;
Simple: the implementation of the algorithm should be relatively simple;
Low memory: The algorithm should not rely on too many historical blocks, and use as few "memory variables" as possible. Assuming that there are the latest ten blocks, add the memory variables stored in the headers of these ten blocks, and these blocks can be used for the calculation of the algorithm;
Unbreakable: The algorithm should not give miners too much incentive to tamper with the time stamp or mine pools to repeatedly add or delete computing power
first level title
Gas and fees
All transactions in Bitcoin are roughly the same, so their network costs are modeled in a single unit. Transactions in Ethereum are more complex, so transaction fees need to take into account many aspects of the account, including network bandwidth costs, storage costs, and computation costs. Not least, the Ethereum programming language is Turing-complete, so transactions can use any amount of bandwidth, storage, and computation costs; how much will end up being used cannot be reliably predicted (due to the so-called "Turing halting problem") ) (Proofreading Note: That is, there is no reliable way to assert that any program executable on a Turing machine will terminate within a finite number of steps). Preventing denial-of-service attacks using infinite loops is a key goal of ours.
The basic mechanics of Ethereum transaction fees are as follows:
Each transaction must specify the amount of gas it is willing to consume (that is, specify the value of startgas), and the fee that it is willing to pay for each unit of gas (that is, gasprice). Deducted from the account; (Proofreading Note: The startgas here is the gaslimit we are used to now.)
All operations during transaction execution, including reading and writing databases, sending messages, and calculations at each step will consume a certain amount of gas;
If the transaction is completed and the consumed gas value is less than the specified limit value, the transaction is executed normally, and the remaining gas value is assigned to the variable gas_rem; after the transaction is completed, the sender will receive the returned ether with the value of gas_rem * gasprice, The reward to the miners is (startgas - gas_rem) * gasprice worth of ether;
If the gas is exhausted during the execution of the transaction, all executions will be restored to the original state, but the transaction is still valid, but the only result of the transaction is to pay the miners with the value of startgas * gasprice, and the other remains unchanged;
When a contract sends a message to another contract, it is possible to set a gas limit on sub-executions caused by the message. If the sub-execution runs out of gas, the sub-execution is restored, but the gas is still consumed. (Proofreading note: As of the time of proofreading this article (July 9, 2021), this has not changed, but it may change in the future. See "EVM Features Worth Considering Removal》)
If the transaction didn't need to specify a gas limit, then a malicious user could send a transaction with a loop of billions of steps. No one can process such a transaction, because it may take a long time to process such a transaction; but no one can inform the miners on the network in advance, which will lead to a denial of service vulnerability.
An alternative to strict gas counts are time limits, but they're unlikely to be useful because they're too subjective (some computers are faster than others, and even if everyone's computers are the same it's still possible to get things wrong).
The entire value of startgas * gasprice should be set at the beginning, so that the account will not be "bankrupt" during transaction execution and unable to continue to pay gas fees. Checking the balance while executing it also doesn't work, because the account can put the balance elsewhere.
If the transaction execution will not be fully reverted (rolled back) in the event of insufficient gas, the contract must employ strong safety measures to prevent the contract from changing.
If sub-restrictions do not exist, malicious accounts can perform denial of service attacks on other contracts. The attacker can first reach a consensus with the victim contract, and then insert an infinite loop at the beginning of the calculation process, then send a message to the victim contract or any attempt to remedy the victim contract, the entire transaction will be deadlocked. (Proofreading Note: This sentence is also difficult to understand.)
Requiring transaction senders, rather than contracts, to pay for gas greatly increases developer operability. Early versions of Ethereum paid for gas by contracts, which led to a rather serious problem: each contract had to implement "gatekeeper" code that ensured that each incoming message provided enough ether for the contract to consume .
For any transaction, a base fee of 21000 gas will be charged. These fees can be used to pay for the cost of running the elliptic curve algorithm designed to recover the sender's address from the signature, as well as the hard drive and bandwidth space spent to store the transaction.
Transactions can include an unlimited amount of "data". Certain opcodes in the virtual machine that allow contracts receiving such transactions to access the data. The "fixed consumption" rule for data is: 4 gas per zero byte, 68 gas per non-zero byte. This formula arises because most transactions sent by users to contracts consist of a series of 32-byte parameters, most of which have many leading zero bytes. This structure may seem inefficient, but due to the compression algorithm, it is actually quite efficient. We hope that this structure can replace other more complex mechanisms that strictly wrap parameters according to the expected number of bytes, resulting in a significant increase in the complexity of the compilation phase. This is an exception to the sandwich complex model, but it is also a reasonable model due to the cost-benefit ratio.
The consumption of the operation code SSTORE used to set the account storage item is: 1) When changing a zero value to a non-zero value, it consumes 20000 gas; 2) changing a zero value to a zero value, or a non-zero value to a non-zero value, consumes 5000 gas; 3) Change a non-zero value to a zero value and consume 5000 gas; in addition, 15000 gas will be refunded after the transaction is successfully executed (that is, the transaction is executed without exhausting the gas). The upper limit of the refund amount is 50% of the total gas consumed by the transaction. This gives people a small incentive to clear stored items. We have noticed that because of the lack of such incentives, the storage space of many contracts is not used effectively, which leads to the rapid expansion of stored data. This design provides most of the benefits of the "continuous rent for storage items" model without losing the guarantee that the contract, once established, can exist indefinitely. The delayed refund mechanism is necessary because it can prevent denial-of-service attacks: the attacker can send a transaction with a small amount of gas, and clear a large number of storage items in a cycle until the gas is used up, which consumes a lot of verification computing power, but the actual It doesn't really clear storage, and it doesn't cost a lot of gas. The 50% cap is to ensure that the miners who package the transaction can still determine the upper limit of the calculation time to execute the transaction.
(Proofreading Note: First of all, the gas consumption of state access opcodes such as SSTORE has been changed many times with the hard fork of Ethereum. As of July 2021, the latest value can be found in "Overview of Berlin's upgrade content"; in the foreseeable future, the value of this opcode will continue to change; secondly, the gas refund mechanism here has not been activated to alleviate the problem of state data expansion, but has worsened the problem, because people can change the value of the gas price When the gas price is low, a large amount of garbage data is written, and when the gas price is high, these data are cleared to obtain gas. This is the principle of "GasToken". It has been confirmed that the gas refund mechanism will be changed in the "London" fork, see "Ethereum "London" Upgrade Preview》。)
The message data provided by the contract has no cost. Because there is no need to actually copy any data during the message call, the call data (call data) can simply be regarded as a pointer to the memory of the parent contract, which will not change when the child process executes.
Memory is an array that can be expanded infinitely. However, every expansion of 32 bytes of memory will consume 1 gas cost, and less than 32 bytes are counted as 32 bytes. (Proofreading note: memory is generally translated as memory, but in the context of Ethereum, it is one of the three types of EVM because of storing data, so it is not translated to show its particularity.)
The calculation time of some opcodes is extremely dependent on parameters, and the gas overhead calculation is dynamically changed. For example, the cost of EXP is exponential (10 gas + 10 gas/byte, i.e., x^0 = 1 gas, x^1 ... x^255 = 2 gas, x^256 ... x^65535 = 3 gas ,etc). Copy opcodes (e.g. CALLDATACOPY, CODECOPY, EXTCODECOPY) have an overhead of 1 gas + 1 gas/32 bytes (rounded up; the rules for the LOG opcode are similar). The overhead of Memory expansion is not included here. If it is included, it will become a square attack vector (50,000 CALLDATACOPY, consuming 50,000 gas each time, the calculation amount should be 50,000^2, but if you do not use the dynamic charging rule, you only need to pay ~50,000 gas).
Opcode CALL (and CALLCODE ) cost an additional 9000 gas if the value is non-zero. This is because any value transfer will cause the archive node's history storage to grow significantly. Please note that the actual consumption of the operation is 6700; but on this basis, we forcefully increase a gas value that is automatically given to the receiver, and this value is at least 2300. This is done so that the wallet accepting the transaction has at least enough gas to generate the log. (proofreading note: see "EVM Features Worth Considering Removal》)
The points mentioned above must be met, for example:
Gas consumption calculation has the following characteristics:
Another important part of the gas mechanism is the economics embodied in the gas price itself. In Bitcoin, the default approach is to take purely voluntary fees, with miners acting as gatekeepers and dynamically setting the minimum fee. In Ethereum, transaction senders are allowed to set any number of gas. This method is very popular in the Bitcoin community because it is the embodiment of a "market economy": allowing miners and traders to determine prices based on supply and demand. However, the problem with this approach is that transaction processing does not follow market principles. Although transaction processing can be thought of as a service provided by miners to senders (which sounds intuitive), in fact every transaction processed by a miner must be processed by every node in the network, so the majority of transaction processing The costs are all borne by third party agencies, not the miners who decide whether to dispose of it. Therefore, the "tragedy of the commons" problem is very likely to occur.
virtual machine
virtual machine
The Ethereum Virtual Machine is the engine that executes transaction codes, and it is also the core difference between Ethereum and other systems. Note that the virtual machine should be considered separately from the "contract and message model". For example, the SIGNEXTEND opcode is a function of the virtual machine, but in fact "a contract can call other contracts and specify the gas limit for sub-calls" is part of the "contract and message model".
The design goals of the EVM are as follows:
Simple: as few and low-level opcodes as possible; as few data types as possible; as few virtual machine structures as possible;
The result is unambiguous: In the VM specification, there is no room for possible ambiguity, and the result should be completely deterministic. Also, the calculation step should be precise so that the gas consumption can be measured;
Space saving: EVM components should be as compact as possible;
Specialized for Intended Use: Applications built on the VM should be able to handle 20-byte addresses, and 32-bit custom encrypted values, have modulus operations for custom encrypted, read block and transaction data and Capabilities such as state interaction;
Simple and safe: In order to prevent VMs from being exploited, it should be easy to establish a set of gas consumption cost models;
Optimization friendly: should be easy to optimize so that just-in-time compilation (JIT) and accelerated versions of the VM can be built.
The difference between temporary/permanent storage: Let's first look at what is temporary storage and permanent storage. Temporary Storage: Exists in every instance of a VM and disappears after the VM execution ends. Permanent storage: Exists in the blockchain state layer. Suppose the following tree is executed (S for permanent storage, M for temporary storage):
A calls B;
B set BS[0]=5, BM[0]=9;
B calls C;
C calls B.
At this time, if B tries to read BS[0], it will get the data stored in B before, which is 5; but if B tries to read BM[0], it will get 0, because BM is a temporary storage, and the read When it is fetched, it is a new instance of the virtual machine. In an inner call (inner call), if you set BM[0] = 13 and BS[0] = 17, then both the inner call and the call of C are terminated and return to the outer call (outer call) of B, at this time read Taking M, you'll see BM[0] = 9 (this value was set in the last instance of the same VM execution), BS[0] = 17 . If B's external call ends, and A calls B again, we will see BM[0] = 0 and BS[0] = 17. The purpose of this difference is: 1. Each execution instance is allocated with memory space, which will not be degraded by loop calls, which makes safe programming easier. 2. Provide an in-memory form that can be operated quickly: because the tree needs to be modified, storage updates are necessarily slow.
Stack/memory mode: In the early days, there were three types of computing states (except the program counter pointing to the next instruction): stack (stack, a 32-byte standard LIFO stack), memory (memory, a temporary byte array that can be extended indefinitely), Storage items (storage, permanent storage). On the temporary storage side, the alternative to stacks and memory is the memory-only paradigm, or a hybrid of registers and memory (there is not much difference between the two, registers are essentially a kind of memory). In this case, each instruction has three arguments, for example: ADD R1 R2 R3: M[R1] = M[R2] + M[R3] . The reason for choosing the stack paradigm is obvious, it makes the code smaller by a factor of 4.
Word size 32 bytes: In most structures, like Bitcoin, the word size is 4 or 8 bytes. 4 or 8 bytes is too restrictive for memory addresses and cryptographic calculations. It is difficult to establish a correspondingly safe gas model without limiting the size. 32 bytes is an ideal size because it is enough to store the large values and addresses required by many cryptographic algorithms without being too large to cause inefficiency.
We have our own virtual machines: our virtual machines are developed in languages like java, Lisp and Lua. We think it is worthwhile to develop a specialized virtual machine because: 1) Our VM specification is much simpler than many other virtual machines, because other virtual machines pay less for complexity, that is, they are easier to change. However, every additional bit of complexity in our scheme creates barriers to intensification development and introduces potential security flaws, such as consensus errors, which make our complexity cost high;2 ) Our VM is more specialized, such as supporting 32 bytes; 3) We will not have complex external dependencies, which will cause our installation to fail; 4) A complete review mechanism can be specific to special security requirements; Even using an external VM doesn't save much work.
A variable, expandable memory size is used: a fixed memory size is an unnecessary constraint, too small or too large. If the memory size is fixed, it is necessary to check whether the access exceeds the boundary every time the memory is accessed, which is obviously not efficient.
1024 Call depth limit: Many programming languages crash because the call depth is too deep before the memory overflows. So it is not enough to use the block gas limit as a limit.
Untyped: just for brevity. However, DIV, SDIV, MOD, SMOD use signed or unsigned opcodes (it turns out signed and unsigned are equivalent for opcodes ADD and MUL); Cases are simple, e.g. a * b -> (a * b) / 2^32, a / b -> a * 2^32 / b at 32 bit length, +, - and * in integers constant.
Proofreading Note: There is also the following paragraph in the original translation, but its corresponding paragraph has been deleted in the current version of the original text: There is no limit to the stack size: no special reason! In many cases, this design is not strictly necessary; since, the gas overhead and the block gas cap will always act as a cap on the consumption of each resource.
ADDMOD,MULMOD: In most cases, mulmod(a, b, c) = a * b % c, but in the elliptic curve algorithm, the 32-byte modulus operation is used, and the direct execution of a * b % c is actually in Executing ((a * b) % 2^256) % c will give a completely different result. Consensus performing the a * b % c computation of a 32-byte value in a 32-byte space is difficult and tedious.
SIGNEXTEND: The purpose of the SIGNEXTEND opcode is to facilitate type conversion from a large signed integer to a small signed integer. Small signed integers are useful because future just-in-time virtual machines may have the ability to detect long-running code blocks that deal primarily with 32-byte integers, and small signed integers can speed up processing.
SHA3: In the Ethereum code, SHA3 is widely used as a secure, high-strength, variable-length data hash mapping method. Generally, when using memory, you need to use Hash functions to prevent malicious collisions, and you need to use Hash functions when verifying Merkle trees and similar Ethereum data structures. Importantly, hash functions similar to SHA3, such as SHA256, ECRECVOR, RIPEM160, are not included in the form of opcodes, but in the form of pseudo-contracts. The purpose of this is to put them in a separate category, and if and when we come up with a proper "native plugin" system later, more such contracts can be added without the need for extension opcodes.
ORIGIN: The ORIGIN opcode is provided by the sender of the transaction, and its main function is to allow the contract to return the paid gas.
COINBASE: The main role of COINBASE is to: 1) allow sub-coins to contribute to network security; 2) enable miners to act as a decentralized economy to set up sub-consensus-based applications, such as Schellingcoin.
PREVHASH: PREVHASH can be used as a semi-secure source of randomness. Furthermore, it allows contracts to evaluate the previous block's Merkle tree state proof without requiring highly complex "Ethereum light client" recursive structures.
EXTCODESIZE,EXTCODECOPY: The main function is to let the contract check the code of other contracts according to the template, and even simulate them before interacting with other contracts. See: https://lesswrong.com/lw/aq9/decision_theories_a_less_wrong_primer/
JUMPDEST: When the jump destination is limited to a few indexes (in particular, the computational complexity of dynamic destination jumps is O(log (number of valid challenge destinations)), while static jumps are always constant), JIT virtual machines are simpler to implement. Therefore, we need to: 1) restrict valid variable jump destinations; 2) encourage the use of static rather than dynamic jumps. In order to achieve these two goals, we set the following rules: 1) the jump immediately after the push can jump anywhere, not just another jump; 2) other jumps can only jump to JUMPDEST. Restrictions on jumps are necessary so that it is possible to determine whether the current jump is a static jump or a dynamic jump by looking at the previous operation in the code. The lack of need for static jumps is what motivates their use. Disabling jumps into push data also speeds up JIT VM compilation and execution.
LOG: LOG is a log of events.
CALLCODE: This opcode allows a contract to use its own storage items to call "functions" of other contracts in a separate stack space and memory. This allows flexible implementation of standard library code on the blockchain.
SELFDESTRUCT: Allows a contract to delete itself if it no longer needs to exist. SELFDESTRUCT is not executed immediately, but after the transaction is executed. This is because allowing SELFDESTRUCT to roll back after execution would greatly increase the complexity of caching, which is not conducive to an efficient VM implementation.
Original link:
At the same time, EVM also has the following special design:
The function and purpose of some opcodes in this VM are easy to understand, but some are not, and here are some special reasons:
(over)
Original link:
https://eth.wiki/en/fundamentals/design-rationale
Author: Vitalik
Translation & proofreading: kim & A Jian


