├── .gitignore ├── ethereum ├── why-use-golang-to-build-a-blockchain.md ├── ethereum-code-structure.md ├── ethereum-should-do-something-new.md ├── erc1155-token.md ├── dapp.md ├── remix.md ├── metamask.md ├── truffle.md ├── geth.md ├── smart-contracrt-best-practice.md ├── create-an-account.md ├── ethereum-trie.md ├── pos.md ├── why-we-want-a-new-blockchain.md ├── private-key-secp256k1.md ├── cross-chain.md ├── gas-eip-1559.md ├── smart-contracrt.md ├── erc20-token.md ├── mining-start.md ├── transaction.md ├── zero-knowledge-proof.md ├── evm.md ├── mining-chainconfig.md ├── ethereum-account-state.md ├── ethereum-block-and-network.md ├── erc721-token.md └── solidity.md ├── pictures ├── fee1.png ├── fee2.png ├── trie.png ├── chains.png ├── commit.png ├── merkle.png ├── state.webp ├── Patricia.png ├── miner-uml.png ├── evm_process.jpg ├── miner-loop.png ├── tree_change.png ├── contract-demo.png ├── mining-process.png └── evm_code_executed.png └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.xml 3 | *.DS_Store 4 | -------------------------------------------------------------------------------- /ethereum/why-use-golang-to-build-a-blockchain.md: -------------------------------------------------------------------------------- 1 | Fixme -------------------------------------------------------------------------------- /ethereum/ethereum-code-structure.md: -------------------------------------------------------------------------------- 1 | # Ethereum Code Structure 2 | 3 | Fixme 4 | -------------------------------------------------------------------------------- /pictures/fee1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/fee1.png -------------------------------------------------------------------------------- /pictures/fee2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/fee2.png -------------------------------------------------------------------------------- /pictures/trie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/trie.png -------------------------------------------------------------------------------- /pictures/chains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/chains.png -------------------------------------------------------------------------------- /pictures/commit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/commit.png -------------------------------------------------------------------------------- /pictures/merkle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/merkle.png -------------------------------------------------------------------------------- /pictures/state.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/state.webp -------------------------------------------------------------------------------- /ethereum/ethereum-should-do-something-new.md: -------------------------------------------------------------------------------- 1 | # 01. Why Use GoLang to Build a Blockchain? 2 | 3 | Fixme 4 | -------------------------------------------------------------------------------- /pictures/Patricia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/Patricia.png -------------------------------------------------------------------------------- /pictures/miner-uml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/miner-uml.png -------------------------------------------------------------------------------- /pictures/evm_process.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/evm_process.jpg -------------------------------------------------------------------------------- /pictures/miner-loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/miner-loop.png -------------------------------------------------------------------------------- /pictures/tree_change.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/tree_change.png -------------------------------------------------------------------------------- /pictures/contract-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/contract-demo.png -------------------------------------------------------------------------------- /pictures/mining-process.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/mining-process.png -------------------------------------------------------------------------------- /pictures/evm_code_executed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiwensangsang/ethereum-core/HEAD/pictures/evm_code_executed.png -------------------------------------------------------------------------------- /ethereum/erc1155-token.md: -------------------------------------------------------------------------------- 1 | # ERC-1155 2 | 3 | This is a standard that mixes ERC-20 and ERC-1155. 4 | It solves the difficulty of sending NFT in batches, and claims that it has great prospects in the blockchain game industry. 5 | There are currently no prospects. -------------------------------------------------------------------------------- /ethereum/dapp.md: -------------------------------------------------------------------------------- 1 | # DApp 2 | 3 | - Can you describe a decentralized application? 4 | - A decentralized application, or DApp, is an application that runs on a decentralized network such as a blockchain. Unlike traditional applications that rely on a centralized server or authority, DApps operate on a peer-to-peer network of computers, where each participant has an equal say in the decision-making process. DApps are typically open-source and transparent, meaning that anyone can view the code and audit the application's behavior. DApps can be used for a variety of purposes, including finance, gaming, social media, and more. 5 | - Are there any Popular Platforms for Building Blockchain Applications? 6 | - No. 7 | - The diffs betweens DApp and smart contracts? 8 | - Smart contracts are backend services of DApp. -------------------------------------------------------------------------------- /ethereum/remix.md: -------------------------------------------------------------------------------- 1 | # Remix 2 | 3 | Remix is a web-based integrated development environment (IDE) that helps developers write, test and deploy smart contracts. A smart contract is a self-executing computer program on the Ethereum platform that manages digital assets and data. 4 | 5 | Remix provides a visual interface and various development tools so that developers can more easily write, debug and test smart contracts. One particularly useful feature is Remix's Solidity editor, which provides features such as basic syntax highlighting and code formatting for smart contract writing. 6 | 7 | In addition, Remix also provides a connection to the Ethereum network and can interact with Ethereum nodes. By connecting to an Ethereum node, developers can test the function and performance of the contract, and perform necessary tests and verifications before deploying the contract. 8 | 9 | In Remix, various Ethereum nodes can be connected, such as local nodes, test network nodes, and main network nodes. These nodes can provide different network environments and testing options to help developers test different aspects and scenarios of contracts. At the same time, Remix also provides various plug-ins and extensions to enhance its functions and experience. -------------------------------------------------------------------------------- /ethereum/metamask.md: -------------------------------------------------------------------------------- 1 | # Metamask 2 | 3 | Metamask is a popular cryptocurrency wallet and browser extension that allows users to interact with the Ethereum blockchain. It is available as a browser extension for Google Chrome, Firefox, Brave, and Microsoft Edge, as well as a mobile app for iOS and Android devices. 4 | 5 | Metamask connects to the Ethereum network through a variety of nodes, including Infura, which is a third-party service that provides access to the Ethereum network, as well as other public and private nodes. 6 | 7 | Compared to traditional Ethereum wallets, Metamask does not support certain features such as: 8 | 9 | 1. Storing tokens from other blockchains: Metamask is primarily designed for interacting with the Ethereum blockchain and does not support storing tokens from other blockchains. 10 | 2. Hardware wallet integration: While Metamask allows users to connect to a hardware wallet, it does not fully support hardware wallet integration like some other wallets do. 11 | 3. Advanced smart contract functionality: Metamask is primarily focused on providing a user-friendly interface for interacting with the Ethereum network, and as such, it does not support some of the more advanced smart contract features that more technical users may require. 12 | 13 | Despite these limitations, Metamask is a powerful and user-friendly tool for interacting with the Ethereum blockchain, and it has become a popular choice for both novice and experienced cryptocurrency users. -------------------------------------------------------------------------------- /ethereum/truffle.md: -------------------------------------------------------------------------------- 1 | # Truffle 2 | 3 | Truffle is an open source framework for Ethereum blockchain development that provides a set of tools and conventions that make the development, testing, and deployment of Ethereum smart contracts easier and more efficient. 4 | 5 | The main purpose of Truffle is to speed up the development process of Ethereum smart contracts. It provides many development tools, such as contract compiler, interactive console, automated testing framework, deployment manager, etc., which can help developers quickly write, test and deploy smart contracts. In addition, Truffle also provides some convenient development conventions, such as contract file structure, best practices for writing contracts, etc. These conventions allow developers to understand and write contracts more quickly. 6 | 7 | The benefits of using Truffle include: 8 | 9 | Accelerate the development of smart contracts: Truffle provides many development tools and conventions that allow developers to write, test and deploy smart contracts more quickly. 10 | 11 | Improve development efficiency: Truffle's automated testing framework can help developers quickly test contracts and find problems in time, thereby improving development efficiency. 12 | 13 | Improve contract quality: Best practices for using Truffle can help developers write better contract code and reduce potential security vulnerabilities and bugs. 14 | 15 | Integration with other tools and platforms: Truffle can be integrated with other development tools and platforms (such as Ganache, Infura, etc.) to better support the developer's workflow. 16 | 17 | In short, Truffle is a powerful Ethereum development framework that can help developers develop smart contracts faster and more efficiently while improving the quality and security of contracts. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ethereum Core 2 | This project will give a detailed introduction to the technical history, working principles, development trends, and security discussions of Ethereum. It will also attempt to build a minimal blockchain project based on Ethereum. 3 | 4 | 5 | 6 | ### Ethereum: new blcokchain 7 | 8 | 0. [Why We Want a New Blockchain?](./ethereum/why-we-want-a-new-blockchain.md) 9 | 1. [Ethereum Trie](./ethereum/ethereum-trie.md) 10 | 2. [Ethereum Account and State](./ethereum/ethereum-account-state.md) 11 | 3. [Ethereum Block and Network](./ethereum/ethereum-block-and-network.md) 12 | 4. [Mining: ChainConfig](./ethereum/mining-chainconfig.md) 13 | 5. [Mining: Start](./ethereum/mining-start.md) 14 | 6. [PoS](./ethereum/pos.md) 15 | 7. [Zero Knowledge Proof and zk-SNARK](./ethereum/zero-knowledge-proof.md) 16 | 8. [Cross Chain](./ethereum/cross-chain.md) 17 | 18 | 19 | 20 | ### Account and Transaction 21 | 22 | 1. [Create an Account](./ethereum/create-an-account.md) 23 | 2. [Private Key: secp256k1](./ethereum/private-key-secp256k1.md) 24 | 4. [Transaction with ECDSA](./ethereum/transaction.md) 25 | 6. [Gas and EIP-1559](./ethereum/gas-eip-1559.md) 26 | 27 | 28 | 29 | ### Smart Contract 30 | 31 | 1. [What is the Importance of EVM in Ethereum](./ethereum/evm.md) 32 | 2. [What is a Smart Contract?](./ethereum/smart-contracrt.md) 33 | 3. [Solidity](./ethereum/solidity.md) 34 | 4. [Tether:Create an ERC-20 Token](./ethereum/erc20-token.md) 35 | 5. [BoredApeYachtClub:Create an ERC-721 Token](./ethereum/erc721-token.md) 36 | 6. [ERC-1155 Token](./ethereum/erc1155-token.md) 37 | 7. [Smart Contract Best Practice](./ethereum/smart-contracrt-best-practice.md) 38 | 8. [DApp](./ethereum/dapp.md) 39 | 40 | 41 | 42 | ### Security 43 | 44 | 1. [How to Protect a Smart Contract?](ethereum/how-to-protect-smart-contract.md) 45 | 1. [How to Attack a Smart Contract?](ethereum/how-to-attack.md) 46 | 47 | 48 | 49 | 50 | ### Tools 51 | 52 | 1. [Geth](./ethereum/geth.md) 53 | 2. [Metamask](./ethereum/metamask.md) 54 | 3. [Truffle](./ethereum/truffle.md) 55 | 4. [Remix](./ethereum/remix.md) 56 | -------------------------------------------------------------------------------- /ethereum/geth.md: -------------------------------------------------------------------------------- 1 | # Geth 2 | 3 | - What is Geth? 4 | 5 | - Geth is an Ethereum client implemented in the Go programming language that allows users to interact with the Ethereum network. It provides a command-line interface for running a full node that can verify transactions, execute smart contracts, and participate in the consensus process. 6 | 7 | - What RPCs can you use to connect to Geth clients over the network? 8 | 9 | - Geth supports several Remote Procedure Call (RPC) APIs that allow external applications to communicate with a Geth client over the network. Some of the most commonly used RPCs include: 10 | 11 | - eth_call: Executes a message call transaction on the Ethereum network. 12 | 13 | - eth_sendTransaction: Sends a transaction to the network for execution. 14 | 15 | - eth_getBalance: Returns the balance of an Ethereum account. 16 | 17 | - eth_blockNumber: Returns the number of the most recent block. 18 | 19 | - What is Geth's "fast" sync, and why is it faster? 20 | 21 | - Geth's "fast" sync is a synchronization mode that allows new nodes to quickly synchronize with the Ethereum network. In fast sync mode, instead of downloading and processing every block from the genesis block, Geth downloads only the block headers and uses them to create a snapshot of the state of the network at a recent block. This allows new nodes to catch up to the current block more quickly. 22 | 23 | - How to connect two Geth clients using IPC-RPC? 24 | 25 | - To connect two Geth clients using IPC-RPC, you can specify the IPC file path using the "--ipcpath" option when starting each client. For example: 26 | 27 | - Geth client 1: geth --ipcpath /path/to/geth1.ipc 28 | 29 | - Geth client 2: geth --ipcpath /path/to/geth2.ipc 30 | 31 | - Where are accounts stored in the Geth client? 32 | 33 | - Accounts in the Geth client are stored in the keystore directory, which is typically located in the user's home directory under ".ethereum/keystore". Each account is represented by a file in the keystore directory that contains the account's private key. 34 | 35 | - How to use Geth to initiate a transaction to an account? 36 | 37 | - To initiate a transaction to an account using Geth, you can use the "eth_sendTransaction" RPC. The RPC takes a JSON object as an argument, which includes the sender's address, the recipient's address, the amount to send, and other transaction parameters. For example: 38 | - eth_sendTransaction({from: "0x123...", to: "0x456...", value: "1000000000000000000"}) 39 | 40 | - This would send 1 ETH from the account at address "0x123..." to the account at address "0x456...". 41 | 42 | - Can the Geth client be used for mining? 43 | 44 | - Yes, the Geth client can be used for mining Ethereum. Geth includes a built-in miner that allows users to mine Ether and participate in the consensus process. To start mining with Geth, you can use the "miner.start" RPC. For example: miner.start(). This would start the miner and begin searching for new blocks to mine. -------------------------------------------------------------------------------- /ethereum/smart-contracrt-best-practice.md: -------------------------------------------------------------------------------- 1 | # Smart Contract Best Practice 2 | 3 | ### Best Practice 4 | 5 | - If I have a huge project, do I need to keep all related smart contracts in one file? 6 | - No, you don't need to keep all related smart contracts in one file. You can put them in separate files and then use the Solidity import statement to include them in the main contract. 7 | - Can I only import local files in smart contract? 8 | - Yes 9 | - What is an ABI? 10 | - ABI (Application Binary Interface) refers to the specification of the functions and parameters required to interact with a smart contract. 11 | - Is it free to check the status of the smart contract? 12 | - Yes 13 | - How to set the Ether balance limit of the smart contract, what will happen if you send excess Ether to the smart contract with balance limit? 14 | - You can use the payable function and require statement to set the Ether balance limit of a smart contract. If you send excess Ether to a smart contract with a balance limit, the excess Ether will be rejected and returned to the sender's account. 15 | - How to set the value of msg.val in the smart contract account? 16 | - msg.value is a global variable that stores the amount of Ether carried by the current transaction. You can use the payable function and require statement to set the value of msg.value to any value you want. 17 | - Will the trader get a refund if the cost of executing the smart contract is less than the gas he paid? 18 | - It depends on the specific smart contract and the platform it is deployed on. Some smart contracts may have a refund mechanism built-in, while others may not. In general, if the cost of executing the smart contract is less than the gas paid by the trader, the excess gas will be lost and not refunded. 19 | - In what ways can two smart contracts interact? 20 | - Two smart contracts can interact with each other in various ways, such as through function calls, events, and messaging. Function calls allow one smart contract to invoke a function on another smart contract, passing in parameters and receiving return values. Events allow smart contracts to emit and listen for events, enabling them to communicate with each other and react to specific conditions. Messaging is a more complex form of interaction that involves sending and receiving messages between smart contracts, allowing for more sophisticated forms of communication and coordination. 21 | 22 | 23 | 24 | ### Verification 25 | 26 | What are the steps involved in smart contract verification? 27 | 28 | 1. Normalized Smart Contracts: Transform smart contracts into a mathematical model or specification so that their correctness can be more easily verified. 29 | 30 | 2. Static Analysis: Perform static analysis on the contract code to identify possible vulnerabilities and errors in the code. 31 | 32 | 3. Dynamic testing: Dynamic testing of the contract to ensure that the contract can be executed as expected in actual execution. 33 | 34 | 4. Formal Verification: Smart contracts are verified using formal methods to prove that they conform to the specification. 35 | 36 | 5. Manual review: A professional audit team will manually review the contract to find other possible loopholes and security issues. 37 | 38 | 39 | 40 | ### Deploy 41 | 42 | - How to deploy a file with multi smart contracts? 43 | - When attempting to deploy a file with multiple smart contracts, each smart contract will need to be compiled and deployed separately. This is because each smart contract has its own address and bytecode and needs to be deployed independently of other smart contracts. 44 | - If you're using the Ethereum Virtual Machine (EVM), you can use development tools like Truffle to compile and deploy smart contracts. Truffle can help you automate this process and ensure that each contract is deployed correctly. 45 | - When deploying multiple smart contracts, you need to ensure that the communication between the smart contracts is correct. This can be achieved by defining interfaces and calling functions between smart contracts. You also need to ensure that each smart contract has access to the other contracts it needs. 46 | - In summary, deploying a file with multiple smart contracts requires separate compilation and deployment, and ensuring correct communication and dependencies between smart contracts. 47 | 48 | 49 | 50 | ### Test 51 | 52 | To be done. -------------------------------------------------------------------------------- /ethereum/create-an-account.md: -------------------------------------------------------------------------------- 1 | # Create an Account 2 | 3 | There are two types of accounts in Ethereum, 4 | 5 | 1. Externally Owned Account (EOA) 6 | 2. Contract Account. 7 | 8 | An EOA is a regular account controlled by a private key. In Ethereum, EOAs manage their assets and transactions through their private keys. EOAs send Ether or call contracts by signing transactions with their private keys and then broadcasting them to the Ethereum network. 9 | 10 | A Contract Account is an account managed by contract code, also known as a smart contract. It contains programmable code and persistent storage space that can be invoked and executed by other accounts. Contract accounts can receive Ether and other tokens and process them according to predetermined logic. 11 | 12 | The main difference between Contract Accounts and EOAs is that Contract Accounts can implement more complex logic through code and can enable automation of transactions, smart contracts, decentralized applications, and other features. Additionally, Contract Accounts have their own address and private key, but the private key is managed by the contract code rather than an individual. 13 | 14 | 15 | 16 | ```go 17 | // Account is the Ethereum consensus representation of accounts. 18 | // These objects are stored in the main account trie. 19 | type Account struct { 20 | Nonce uint64 21 | Balance *big.Int 22 | Root common.Hash // merkle root of the storage trie 23 | CodeHash []byte 24 | } 25 | ``` 26 | 27 | 28 | 29 | Nonce: If it is an EOA account, it indicates the serial number of the sending transaction; if it is a CA account, Nonce indicates the serial number of the contract creation 30 | 31 | Balance: Indicates the balance of the account, the account balance corresponding to the account address 32 | 33 | Root: store the root of the merkle tree, if it is an EOA account root is nil 34 | 35 | CodeHash: EVM Code bound to the account, if it is EOA, CodeHash is nil 36 | 37 | 38 | 39 | ### Create 40 | 41 | Use this to create, 42 | 43 | ```go 44 | personal.newAccount() 45 | 46 | func (ks *KeyStore) NewAccount(passphrase string) (accounts.Account, error) { 47 | _, account, err := storeNewKey(ks.storage, crand.Reader, passphrase) 48 | if err != nil { 49 | return accounts.Account{}, err 50 | } 51 | // Add the account to the cache immediately rather 52 | // than waiting for file system notifications to pick it up. 53 | ks.cache.add(account) 54 | ks.refreshWallets() 55 | return account, nil 56 | } 57 | 58 | // Get PubKey, PrevKey and address 59 | func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Account, error) { 60 | key, err := newKey(rand) 61 | if err != nil { 62 | return nil, accounts.Account{}, err 63 | } 64 | a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.JoinPath(keyFileName(key.Address))}} 65 | if err := ks.StoreKey(a.URL.Path, key, auth); err != nil { 66 | zeroKey(key.PrivateKey) 67 | return nil, a, err 68 | } 69 | return key, a, err 70 | } 71 | 72 | func newKey(rand io.Reader) (*Key, error) { 73 | privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand) 74 | if err != nil { 75 | return nil, err 76 | } 77 | return newKeyFromECDSA(privateKeyECDSA), nil 78 | } 79 | 80 | func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) { 81 | k, err := randFieldElement(c, rand) 82 | if err != nil { 83 | return nil, err 84 | } 85 | ​ 86 | priv := new(PrivateKey) 87 | priv.PublicKey.Curve = c 88 | priv.D = k 89 | priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes()) 90 | return priv, nil 91 | } 92 | func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) { 93 | params := c.Params() 94 | b := make([]byte, params.BitSize/8+8) 95 | _, err = io.ReadFull(rand, b) 96 | if err != nil { 97 | return 98 | } 99 | ​ 100 | k = new(big.Int).SetBytes(b) 101 | n := new(big.Int).Sub(params.N, one) 102 | k.Mod(k, n) 103 | k.Add(k, one) 104 | return 105 | } 106 | func newKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key { 107 | id := uuid.NewRandom() 108 | key := &Key{ 109 | Id: id, 110 | Address: crypto.PubkeyToAddress(privateKeyECDSA.PublicKey), 111 | PrivateKey: privateKeyECDSA, 112 | } 113 | return key 114 | } 115 | ``` 116 | 117 | 118 | 119 | Get Private Key => Get Public Key by Private Key => Get Address by Public Key 120 | -------------------------------------------------------------------------------- /ethereum/ethereum-trie.md: -------------------------------------------------------------------------------- 1 | # Trie 2 | 3 | 4 | 5 | Trie (Merkle Patricia Tree, also known as MPT) is a tree structure used to encrypt and store any (key, value) data pair in ethereum. Its insertion, search and deletion efficiency are all O(log(N)), but it is simpler and easier to understand than other tree structures such as red-black trees, and it also has the characteristics of Merkle trees. 6 | 7 | 8 | 9 | Ethereum accounts have multiple attributes (balance, code, storage information), and attributes (status) need to be updated frequently. Therefore, a data structure is needed to meet several requirements: 10 | 11 | 1. A new tree root can be quickly calculated after performing an insert, modify, or delete operation without recalculating the entire tree. 12 | 2. Even if the attacker deliberately constructs a very deep tree, its depth is limited. Otherwise, an attacker could perform a denial of service attack by deliberately building a tree deep enough that each tree update is extremely slow. 13 | 3. The root value of the tree depends only on the data, not on the order of updates. Updating in a different order, or even recomputing the tree from scratch will not change the root value of the tree. 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ### Normal Trie 22 | 23 | > Trie, also known as prefix tree or **dictionary tree**, is an ordered tree used to save associative arrays, the keys of which are usually strings. Unlike a binary search tree, the key is not stored directly in the node, but is determined by the node's position in the tree. All descendants of a node have the same prefix, which is the string corresponding to this node, and the root node corresponds to the empty string. 24 | 25 | ![trie](../pictures/trie.png) 26 | 27 | In the figure above, each node is actually just a part of the key, or a character of the key. When traversing down according to a certain key until the last character of the key, the value corresponding to the key is also found. 28 | This way of looking up value is exactly the same as looking up a dictionary m 29 | 30 | 31 | 32 | ![Patricia](../pictures/Patricia.png) 33 | 34 | This is how we save 8 key-value pairs. 35 | 36 | ```text 37 | Key value 38 | 6c0a5c71ec20bq3w 5 39 | 6c0a5c71ec20CX7j 27 40 | 6c0a5c71781a1FXq 18 41 | 6c0a5c71781a9Dog 64 42 | 6c0a8f743b95zUfe 30 43 | 6c0a8f743b95jx5R 2 44 | 6c0a8f740d16y03G 43 45 | 6c0a8f740d16vcc1 48 46 | ``` 47 | 48 | #### **Merkle Tree** 49 | 50 | Merkle Tree, also commonly called Hash Tree, as the name suggests, is a tree that stores hash values. 51 | The main function of the Merkle Tree is that when the Top Hash is obtained, the hash value represents the information summary of the entire tree. When any data in the tree changes, the value of the Top Hash will change. The value of Top Hash will be stored in the block header of the blockchain. 52 | 53 | ![merkle](../pictures/merkle.png) 54 | 55 | 56 | 57 | ### Ethereum Trie 58 | 59 | Every time Ethereum executes a transaction, the state of the world corresponding to Ethereum changes. As a public chain platform, Ethereum has a large number of states corresponding to a large number of contracts. Rebuilding the state tree every time a state change occurs will undoubtedly consume huge computing resources. To solve this problem, Ethereum proposes a method of incrementally modifying the state tree. Every time the state of Ethereum changes, the original MPT tree will not be modified, but some branches will be created, as shown in the figure below; 60 | 61 | 62 | 63 | ![tree_change](..\pictures\tree_change.png) 64 | 65 | Every time the state of Ethereum changes, it will only affect a small number of nodes in the world state MPT tree. The newly generated world state tree only needs to recalculate the hashes of a small number of affected nodes and the nodes connected to them. 66 | 67 | The state of Ethereum is very suitable for storage by MPT tree. The characteristics of MPT tree are very consistent with the characteristics of Ethereum state. When using MPT tree to store the state of Ethereum, it can bring the following advantages; 68 | 69 | 1. When the balance of an account changes, the hash of the corresponding path also changes, and then the hash value on the corresponding path is updated from the bottom up until the State Root, so that the minimum number of hashes can be calculated. 70 | 2. The full node in Ethereum maintains an incremental MPT state tree, because each block modifies only a small part of the world state. **Incremental modification** is not only conducive to block rollback, but also saves overhead. 71 | 3. Temporary block forks are common in Ethereum, but due to the complexity of Ethereum smart contracts, it is difficult to roll back the state according to the contract code if the original state is not recorded. -------------------------------------------------------------------------------- /ethereum/pos.md: -------------------------------------------------------------------------------- 1 | # PoS 2 | 3 | 4 | 5 | The consensus mechanism is the method to ensure the consistency of each transaction in the blockchain. 6 | As an ordinary user, it is very difficult to run a full node to verify and record data on the blockchain. 7 | At present, to run an Ethereum full node, at least 800G of data must be stored, and the number is still increasing. The computing power of Ethereum miners is becoming more and more concentrated, and the full nodes are also becoming more and more concentrated. This is obviously detrimental to the security of the entire protocol. 8 | 9 | One of the goals of Ethereum 2 is to allow more ordinary people to participate in the consensus mechanism, and to make it easier for more people to run an Ethereum node. 10 | 11 | Therefore, Ethereum 2 introduces these two points: 12 | 13 | 1. POS 14 | 2. shard 15 | 16 | 17 | 18 | ### Proof of Stake 19 | 20 | The consensus algorithm used by Ethereum, Bitcoin and many mature blockchains is POW, Proof of work, and proof of work. Participating in POW is what we often call mining. 21 | 22 | POW participants have to invest a lot of money to buy hardware, and continue to consume electricity to compete to generate blocks and get rewards. 23 | 24 | POW can easily lead to the concentration of computing power to professional miners. 25 | 26 | The participants of POS are called validators—verifiers. 27 | 28 | Validator does not need to purchase special hardware and consume a lot of power. It only needs to run a program on an ordinary computer and pledge a part of virtual assets. On Ethereum it is 32 ETH. 29 | 30 | The entire network randomly selects participants in proportion to the number of participants' pledged assets and the length of participation to generate new blocks and receive rewards. 31 | 32 | 33 | 34 | ### Shard 35 | 36 | To improve the performance of Ethereum, we can of course expand the block size so that each block contains more data. 37 | But this will require nodes that store blocks to have larger hard disks and better network bandwidth. This further increases the cost of mining and running a node. 38 | 39 | So the Ethereum community abandoned this solution. 40 | 41 | The solution that Ethereum wants to adopt is called shard chain. 42 | 43 | Simply put, one chain is not enough, we run multiple chains 44 | 45 | There will be 64 blockchains running at the same time in Ethereum 2, which may increase in the future. 46 | 47 | Another advantage is that the node on the shard only needs to verify and save the data of the current shard, not the data of the entire Ethereum. This can make the node smaller and lighter, reduce the demand for hardware computing power and storage, enable more people to participate, and increase the decentralization and security of the entire Ethereum. 48 | 49 | Can shard be implemented under the POW mechanism? 50 | 51 | The answer is no. Because after sharding, the difficulty of destroying a single shard chain is actually reduced. 52 | 53 | The way POS solves this problem is to let the verifier pledge the ether currency, and if you find that you are sabotaging, you will be fined, or even all the tokens you pledged will be fined. 54 | 55 | But the punishment method of POW is to prevent those who do damage from digging blocks. All he loses is the electricity consumed while mining the blocks. In order to achieve the effect of POS confiscating pledges on POW, it is necessary to confiscate even the bad guys’ mining machines, which is obviously impossible. 56 | 57 | On the other hand, Ethereum's POS mechanism will randomly assign validators' shards. This mechanism also makes it impossible for vandals to stare at a certain chain for damage, thus increasing the difficulty of its attack. 58 | 59 | 60 | 61 | ### Beacon Chain 62 | 63 | The beacon chain is at the heart of Ethereum 2. Its main function is to implement the POS mechanism and coordinate and synchronize each shard chain. There is a chain to control the chain. 64 | 65 | The beacon chain has been launched on December 1, 2020, and users can already use the smart contract on Ethereum to pledge ETH to participate in POS to obtain rewards. 66 | 67 | Although the beacon chain has been launched, its current function is only to verify various basic functions of Ethereum 2 such as POS in the actual combat environment, and it does not have the ability to process transactions and execute smart contracts. Moreover, the currently pledged ETH and the rewards obtained cannot be withdrawn by the lock owner. 68 | 69 | The beacon chain and the current Ethereum blockchain run in parallel, that is, the current operation of Ethereum is basically not affected by the beacon chain. 70 | 71 | 72 | 73 | ### Next 74 | 75 | In the next stage, 64 shard chains will be launched and connected with the beacon chain to form a whole that can cooperate with each other. 76 | 77 | The current Ethereum blockchain is linked into the beacon chain. The official name is the docking. 78 | 79 | The current Ethereum blockchain will become one of the 64 shard chains, which also marks the official exit of POW mining from the stage of Ethereum. -------------------------------------------------------------------------------- /ethereum/why-we-want-a-new-blockchain.md: -------------------------------------------------------------------------------- 1 | # 00.Why We Want a New Blockchain? 2 | 3 | 4 | 5 | #### Pros and Cons about Bitcoin 6 | 7 | Despite some new use cases, such as China developing a crypto RMB based on blockchain and claiming that government allocations can reach the grassroots without any third-party involvement, some people's perception of blockchain is still getting rich overnight and gambling. 8 | 9 | The high valuation of Bitcoin, which is the highest valued cryptocurrency, has largely influenced people's fascination with blockchain technology. However, from 2022 to 2023, the price of Bitcoin fell by about 70% and the financing of the blockchain industry suffered a significant decline as a result. 10 | 11 | A decade ago, from 2012 to 2013, the price of Bitcoin increased dramatically, going from $12 to $1,200. This sparked interest in the technology behind it and countless people began to pursue the technology architecture of Bitcoin, which has since become an industry standard. 12 | 13 | In short, the operation of Bitcoin is as follows. 14 | 15 | - Create a new Wallet. 16 | 17 | 1. Creating a Bitcoin wallet is equivalent to registering a tradeable account on the Bitcoin system. The wallet includes two key pieces of information: a Public Key and a Private Key. The public key can be made public and anyone can send Bitcoins to that address, similar to a bank account. The private key can be used to sign transactions, similar to a password. 18 | 2. https://github.com/bitcoin/bitcoin/blob/master/src/wallet/wallet.cpp 19 | 3. [http://bitaddress.org](https://link.zhihu.com/?target=http%3A//bitaddress.org) 20 | 21 | - Create a New Bitcoin token. 22 | 23 | 1. Transaction Collection: Bitcoin miners gather all unconfirmed transactions, as a "block". 24 | 2. Proof-of-Work: The miner calculates a unique hash value. The miner compares the hash value with a difficulty target (such as the number of leading zeros). 25 | 3. Transaction Confirmation: The block can be submitted to the Bitcoin network, and all transactions contained in it will be confirmed, the miner receives a certain amount of new bitcoins as a reward. 26 | 27 | - Send token to another account. 28 | 29 | 30 | 31 | We can conclude several things: 32 | 33 | 1. The security of transactions greatly depends on the current total computing power and the distribution of computing power in the blockchain. 34 | - If there is only one block and one miner, then the blockchain degenerates into a local database with no actual meaning to its data. 35 | - If a blockchain project's blocks and miners all belong to the same political organization or company, then the blockchain degenerates into a centralized database with no essential difference from using a traditional database, and even slower. 36 | 2. In order to maintain a decentralized blockchain, incentives are needed, such as tokens similar to Bitcoin, or else no one will waste their valuable computing resources on the blockchain. 37 | 3. The higher the economic value of the token, the more people will join the blockchain. 38 | 4. Bitcoin has only one practical function, transfer of funds. 39 | 40 | 41 | 42 | 43 | #### Try to add new features for Bitcoin: Counterparty 44 | 45 | There's an interesting fact that you can make a Bitcoin transfer to yourself. This may seem like a silly thing to do because you have to pay a fee, but it actually serves a purpose. 46 | 47 | In 2014, there was a difference of opinion within the Bitcoin community on what Bitcoin and blockchain were for. A lot of people, including some influencers, agreed that Bitcoin should only focus on transfers, and that blockchain was just for accounting purposes(In Bitcoin). 48 | 49 | However, there were also those who believed that blockchain should have other uses. Looking back now, it's obvious that this was the case, as blockchain's unalterable properties are extremely valuable, and since it has already provided such excellent support for the highly accurate money transfer business, why not develop other businesses as well? In theory, any internet business could migrate their operations to the blockchain (for example, the tweets you send can't be deleted or modified by anyone). 50 | 51 | With this in mind, Counterparty started trying to store more data on the Bitcoin blockchain. Their goal was to simply publish the data to the blockchain and then use other read interfaces to access the data and process it themselves. 52 | 53 | The specific method was to transfer Bitcoin to their own account, and in this transaction, they would place their business data in the special field OP_Return of that transaction, and then spread the transaction, waiting for their business data to be stored by the miner. 54 | 55 | This was obviously a hack-like solution. OP_Return is not designed for this. When this method was publicly announced, a lot of criticism emerged. 56 | 57 | "Counterparty didn't participate in the existing community, they just flipped the switch and started using the Bitcoin P2P nodes as extra data storage." 58 | 59 | https://www.btcstudy.org/2022/07/18/dapps-or-only-bitcoin-transactions-the-2014-debate/ 60 | 61 | This is somewhat reasonable, as Counterparty essentially inserts its own data into the Bitcoin network, and therefore, all Bitcoin miners are required to provide storage services for Counterparty's data. This doesn't seem ideal. 62 | 63 | 64 | 65 | **So, what should engineers do?** 66 | -------------------------------------------------------------------------------- /ethereum/private-key-secp256k1.md: -------------------------------------------------------------------------------- 1 | # Privaty Key: secp256k1 2 | 3 | Elliptic Curve Cryptography (ECC) is a public-key cryptographic algorithm that utilizes the discrete logarithm problem on elliptic curves to achieve secure communication and encryption. 4 | 5 | In ECC, each participant has a public key and a private key. The public key is used for encryption and signature verification, while the private key is used for decryption and signing. The private key is a random number, and the public key is the product of the private key and a point on the elliptic curve. Here's a simple example: 6 | 7 | Let's say we choose an elliptic curve, such as secp256k1, with the following parameters: 8 | 9 | 10 | 11 | ```go 12 | p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 13 | a = 0 14 | b = 7 15 | G = (x, y) 16 | x = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 17 | y = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 18 | n = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 19 | h = 1 20 | ``` 21 | 22 | 23 | 24 | Here, `G` is a base point on the elliptic curve, also known as a generator point, and `n` is the order of the base point, which means adding the base point to itself `n` times will result in the identity element. 25 | 26 | Now, let's generate a public-private key pair. First, we randomly choose a private key `d`, say `12345`. Then, we multiply the base point `G` by the private key `d` to obtain the public key `Q`: 27 | 28 | ```go 29 | Q = d * G = (xq, yq) 30 | (xq, yq) = d * (x, y) mod p 31 | ``` 32 | 33 | 34 | 35 | Plugging in `d=12345` and `G=(x,y)`, we get: 36 | 37 | ``` 38 | (xq, yq) = 12345 * (x, y) mod p 39 | xq = 0xf00f92b4e8b4c4f9d4d4ce4ba77eaa18b49c3a41fa47eeeb79f42bb41dfedc18 40 | yq = 0x58b41f8b62c44e79aafa5d0a6f9362965a5c6a5d0e56df186b35eb66691dcb21 41 | ``` 42 | 43 | Now, we have a public-private key pair, where the private key is `d=12345` and the public key is `(xq, yq)`. 44 | 45 | 46 | 47 | ### Ethereum 48 | 49 | There is no particular reason why Ethereum uses the spec256k1 curve, mainly because the security of this curve has been verified by Bitcoin, and there are a large number of third-party libraries that already support this algorithm. 50 | 51 | secp256k1: 52 | 53 | - y² = x³ + 7 54 | - R:2^256 - 2^32 - 977 55 | - Base point:G = (0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8) 56 | - n:0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 57 | 58 | 59 | 60 | If k=2,the result should be 2G. 61 | 62 | ``` 63 | G = (0, 7) 64 | 2G = G + G = (x3, y3) 65 | ``` 66 | 67 | 68 | 69 | If we use addition calculation, then we directly calculate the address of the public key as (x3=0, y3=14), but unfortunately, the coordinates of the public key obtained by this method are not on the curve y² = x³ + 7. On elliptic curves, we will modify the definition of point plus. 70 | 71 | The self-summation of points on the elliptic curve is the symmetric point along the y-axis to the intersection point of the tangent of the curve and the curve. 72 | 73 | We will use mathematics to prove that the calculation of this point is not complicated. 74 | 75 | for a point(x1, y1}, 76 | 77 | ```go 78 | y' = (3 * x²) / (2 * y) 79 | 80 | // use x1 and y1= sqrt(x³ + 7), 81 | k = y' = (3 * x1²) / (2 * y1) 82 | ``` 83 | 84 | Use y - y1 = k(x - x1) 85 | 86 | ```go 87 | y - y1 = k * (x - x1) 88 | k = (3 * x1²) / ( 2 * y1) 89 | 90 | // remove y 91 | (k * (x - x1))^2 = x³ + 7 92 | 93 | 94 | x³ - k² * x² + (2kx1 - 2ky1) * x + b - (kx1 - y1)² = 0 95 | ``` 96 | 97 | A cubic equation whose solution corresponds to the abscissas x1 , x2 , x3 of the three intersection points of the straight line and the elliptic curve 98 | 99 | According to Vieta's Formulas, the three roots x1 , x2 , x3 of the cubic equation have the following relationship: 100 | 101 | ```go 102 | x1 + x2 + x3 = - b / a = k ^ 2 103 | 104 | // x1 = x2 105 | k = y' = (3 * x1²) / (2 * y1) 106 | 107 | // we get the result. 108 | x3 = k^2 - 2x1 109 | y3 = k(x1 - x3) - x1 110 | ``` 111 | 112 | 113 | 114 | In Ethereum, the base point is usually G=(0,1). The process for generating the public key is as follows: 115 | 116 | 1. Represent the private key as a 32-byte (256-bit) integer. 117 | 2. Use the private key to multiply the elliptic curve base point to get the public key point. Specifically, the public key point is the scalar product of the private key and the base point. The formula is: public key point = private key × G. 118 | 3. The public key point is another point on the elliptic curve, consisting of x and y coordinates. These coordinates are both 256-bit integers and can be represented as hexadecimal strings. 119 | 120 | After generating the public key, Ethereum hashes it to produce a shorter address. This process is called the ripemd160 hash. Essentially, it uses a hashing function to convert the public key to a 20-byte address, which is typically represented as a hexadecimal string for an Ethereum address. The prefix for an Ethereum address is typically 0x, indicating it is a hexadecimal number. 121 | 122 | It's important to note that the Ethereum address is actually a hash of the public key, not the public key itself. This hashing mechanism makes Ethereum addresses shorter and more convenient for transactions and storage. 123 | 124 | 125 | 126 | ### Address 127 | 128 | In the elliptic curve algorithm, the public key is derived from the private key and the elliptic curve base point. Since the private key is a 256-bit random number, the probability of two different private keys generating the same public key is very low, even among all the possible private keys in the universe. Therefore, the uniqueness of the public key is generally guaranteed. 129 | 130 | However, the public key does not necessarily correspond uniquely to an address. In Ethereum, the address is actually a hash of the public key. The hash function converts the public key into a 20-byte address, but different public keys may produce the same hash value, leading to address collisions. 131 | 132 | To avoid this, Ethereum uses a very large address space, typically represented as 2 to the power of 160. This means that in theory, there can be approximately 1.46×10 to the power of 48 possible addresses, making the probability of address collisions very low. Additionally, Ethereum addresses typically check and reject new addresses that are the same as existing addresses, further reducing the likelihood of address collisions and ensuring the uniqueness of addresses. 133 | 134 | 135 | 136 | ### Summary 137 | 138 | 1. The private key of Ethereum can quickly calculate the public key. 139 | 2. It is almost impossible to deduce the private key from the public key. -------------------------------------------------------------------------------- /ethereum/cross-chain.md: -------------------------------------------------------------------------------- 1 | # Cross Chain 2 | 3 | For a long period of time in the early days of the industry, blockchain technology was based on the development of a single chain. At that time, it was generally recognized that the performance optimization and technical upgrade of the blockchain can be completed on a single chain. Once the members of the chain cannot reach an agreement on the development direction of the project, it can only be solved by hard forking or redesigning a chain. 4 | 5 | It was not until 2012 that Ripple Labs proposed the Inter Ledger protocol to solve the coordination problem between different blockchain systems; in 2013, Herlihy proposed the atomic transfer (atomic transfer) scheme on the forum, which became an improved scheme after improvement. One main cross-chain mode, namely the hash lock mode. 6 | 7 | More innovations followed, such as Litecoin, BitShares, and Ethereum, which accelerated the sense of crisis in the Bitcoin core development team. Therefore, in October 2014, BlockStream clearly proposed the concept of side chain for the first time. 8 | 9 | In 2017, cross-chain projects Polkadot and Cosmos proposed a plan to build a cross-chain basic platform, through which all blockchain applications can be compatible. 10 | 11 | 12 | 13 | ### Tendermint 14 | 15 | Cosmos can effectively address the existing problems of Bitcoin and Ethereum, and Cosmos proposes targeted solutions. 16 | 17 | Bitcoin: The code base is very monolithic. All three layers — network, consensus, and application — are mixed together. And the Bitcoin scripting language is limited and user-unfriendly. 18 | 19 | Ethereum: By turning the application layer into the Ethereum Virtual Machine (EVM). Virtual machines are able to process smart contracts, and any developer can deploy smart contracts to the open system of the Ethereum blockchain to build decentralized applications (dApps). But it does not simplify the development of the blockchain itself. It also has the disadvantages of limited scalability, relatively low flexibility granted to developers, and limited sovereignty per application. 20 | 21 | Therefore, Cosmos proposes Tendermint, which is a solution that packages the network and consensus layers of the blockchain into a common engine, allowing developers to focus on application development rather than complex underlying protocols, making it easy to get started. 22 | 23 | While Tendermint is ready for public or private blockchains and proposes POS, it has instant finality: as long as more than one-third of the validators are honest (Byzantine), a fork will never be created. Users can be sure that their transactions are completed immediately after the block is created (something that cannot be done in proof-of-work blockchains such as Bitcoin and Ethereum) and with high security. 24 | 25 | 26 | 27 | ### IBC 28 | 29 | The full name is INTER‑BLOCKCHAIN COMMUNICATION PROTOCOL (inter-chain communication protocol). As the name suggests, it is a communication protocol between chains, which is equivalent to the TCP/IP protocol on the Internet. 30 | 31 | So how does the IBC work? It first needs a middleman-like role called Relayer. Before officially crossing the chain, it first needs to request a connection (Connection) from the two chains and establish a channel (Channel). This channel is bidirectional and bound, because the channel needs to be assigned a unique ID and the number of channels that have been applied for by different chains is different, so we will see that the same channel is assigned different IDs in different chains (For example, the most commonly used channel between Cosmos Hub and Osmosis is Cosmos Hub/Channel-141 <=> Osmosis/Channel-0), when the channel is established, communication can begin. 32 | 33 | Now that you two fellow villagers can start chatting, do you need to find a topic for chatting? Similarly, the content transmitted by IBC also needs to carry the "topic" (Port). For example, the "topic" agreed upon by both parties in the Cosmos ecological token cross-chain is transfer. When you want to cross from chain A to chain B, you first need to initiate a specific cross-chain transaction on chain A; after the transaction is confirmed by chain A, Relayer will forward the transaction and the relevant proof (Proof) to B B chain; B chain then verifies the transaction and its proof, and if it is normal, it will perform related operations according to the established logic. Students who want to learn more can see the official introduction of Cosmos. 34 | 35 | Hey, wait, does my coin crossing from A to B mean that this coin has disappeared from the A chain? Not necessarily, we can look at the specific process: 36 | 37 | You initiate a cross-chain transaction, intending to cross 0.01 OSMO from Osmosis to Cosmos Hub. Because currently Cosmos Hub/Channel-141 <=> Osmosis/Channel-0 is the most commonly used channel, and the agreed "topic" of token cross-chain is transfer. So you specify the sourceChannel as channel-0, the sourcePort as transfer, and the payee on the Cosmos Hub as cosmos186440u3pwts7s3jljngak37xnmy5le8nztf9az 38 | 39 | When the node receives and recognizes that your transaction is a cross-chain transaction and also knows that you want to go from Osmosis to Cosmos Hub, it will not be destroyed at this time, but will transfer your OSMO to the custodial account. Where did this custodial account come from? Is it controlled by an external entity? Don't worry, it's not. The calculation logic of the custody account is: 40 | 41 | ``` 42 | pubkey = sha256( 43 | Buffer.from("ics20-1", "utf-8") 44 | 45 | + Buffer.from([0]) 46 | + Buffer.from(`${sourcePort}/${sourceChannel}`, "utf-8") 47 | ).slice(0, 20) 48 | 49 | Bech32.encode(addressPrefix, pubkey) 50 | // At this point addressPrefix: "osmo", sourcePort: "transfer", sourceChannel: "channel-0" 51 | ``` 52 | 53 | Therefore, we can calculate that the custody account is osmo1a53udazy8ayufvy0s434pfwjcedzqv347h34au. If you are interested, you can click on this address to see how many coins have gone from Osmosis/Channel-0 to Cosmos Hub 54 | 55 | Then Relayer will forward this cross-chain message to Cosmos Hub. After Cosmos Hub receives this message and fully verifies it, it will directly mint 0.01 ibc/14F9BC3E44B8A9C1BE1FB08980FAB87034C9905EF17CF2F5008FC085218811CC to the address cosmos186440u3pwts7s3jljngak37xnmy5le8nztf9az. Not OSMO? What the hell is this? In fact, this is the subtlety. Because this currency is minted out of thin air, and its "code name" (denom) cannot coincide with the existing currency, so it can be obtained in the following way: 56 | 57 | ``` 58 | "ibc/" + sha256(Buffer.from(`${dstPort}/${dstChannel}/${originDenom}`, 'utf-8')).toString("hex").toUpperCase() 59 | // At this point dstPort: transfer, dstChannel: channel-141, originDenom: uosmo 60 | ``` 61 | 62 | Of course, you don’t need to see this unreadable code name during the use of Cosmos Hub. The wallet or browser will intelligently replace its name with OSMO. 63 | 64 | So far, by locking assets in Osmosis, and then minting assets in Cosmos Hub, you have crossed over your assets, and now you can play happily. So what if you want to go back to the Osmosis chain? akin: 65 | 66 | You initiate another cross-chain transaction, specifying sourceChannel as channel-141, sourcePort as transfer and the payee on Osmosis as osmo186440u3pwts7s3jljngak37xnmy5le8n2s64ts 67 | After the node receives the transaction, it detects that you want to return to Osmosis from the Cosmos Hub, so it will directly destroy the coin that was minted out of thin air at this time. 68 | Then, after the Relayer forwards the cross-chain message to Osmosis, Osmosis will transfer the OSMO previously placed on the custodial address to your receiving address after full verification. 69 | Students who want to know more details can also find the answer from the specification and source code 70 | 71 | But if you are smart, you will definitely notice a detail, the process of minting coins out of thin air includes ChannelID. Isn't that equivalent to saying that the same currency will become different currencies when it comes through different channels, and they cannot share liquidity? Yes, this is why there are so many channels between different browser chains, but there is only one with traffic. -------------------------------------------------------------------------------- /ethereum/gas-eip-1559.md: -------------------------------------------------------------------------------- 1 | # EIP-1559 2 | 3 | ### Why need Token in BlockChain? 4 | 5 | In blockchain technology, tokens are units of value or digital assets that are stored and transferred on a blockchain network. Tokens can be used to represent various things, such as cryptocurrencies, digital assets, voting rights, or access to a particular service or platform. 6 | 7 | Tokens are necessary in blockchain for several reasons: 8 | 9 | 1. Facilitating Transactions: Tokens serve as a means of exchange and can be used to facilitate transactions within a blockchain network. For example, in a cryptocurrency blockchain, tokens are used to buy and sell goods and services. 10 | 2. Enabling Smart Contracts: Smart contracts are self-executing contracts with the terms of the agreement between buyer and seller being directly written into lines of code. Tokens are used in smart contracts as a way to execute the terms of the agreement. 11 | 3. Security and Transparency: Tokens can enhance security and transparency within blockchain networks. The use of tokens helps to prevent fraud and other forms of illegal activity by creating a clear and secure record of transactions. 12 | 4. Community Building: Tokens can also be used to incentivize community members to participate in a blockchain network, such as through mining or staking. This helps to build a strong and engaged community that can help to drive the success of the network. 13 | 14 | Overall, tokens are an essential component of blockchain technology, as they serve as the building blocks for the creation of decentralized applications, digital assets, and cryptocurrencies. 15 | 16 | I think the most important reason is that the blockchain is a distributed service that requires a large number of miners to join. Then there needs to be something to seduce others. 17 | 18 | 19 | 20 | ### Wei and Ether 21 | 22 | Both Wei and Ether are units of cryptocurrency in the Ethereum blockchain network. 23 | 24 | Wei is the smallest unit of Ether, similar to Satoshi in Bitcoin. 1 Ether is equal to 10^18 Wei, therefore, 1 Wei is equal to 0.000000000000000001 Ether. 25 | 26 | Ether, the native cryptocurrency in the Ethereum network, is generated through mining and trading activities. 27 | 28 | Smart contracts on the Ethereum network can pay transaction fees in Ether, which are paid in the form of Wei. Transaction fees are collected by miners to incentivize them to validate transactions on the network. 29 | 30 | Below is a more detailed description of how Wei and Ether are minted, modified, queried and deleted: 31 | 32 | 1. Generation: Ether is generated through the mining process of the Ethereum network. Mining is a computationally intensive process designed to verify new transactions and add them to the blockchain. Miners earn new ether by solving complex mathematical puzzles, and they are also rewarded with transaction fees and other rewards. 33 | 34 | 2. Modification: Ether is stored on the Ethereum blockchain and cannot be modified or deleted. They can only be moved by executing a new transaction. When a transaction is executed, ether is transferred from one account to another, which creates a new transaction record on the blockchain. 35 | 36 | 3. Query: You can query the balance and transaction records of Ethereum and Wei through the blockchain browser on the Ethereum network. Users can use the Ethereum Wallet app or other third-party apps to check their account balances. 37 | 38 | 4. Deletion: Ether and Wei are digital assets on the Ethereum blockchain and cannot be deleted. However, if an account is deemed defunct or no longer in use, its balance may be considered "dead" and removed from the blockchain. This will show up on the blockchain explorer as the account balance is zero. 39 | 40 | 41 | 42 | ### Gas 43 | 44 | Gas represents the computational cost required to complete an operation. When a transaction or smart contract is submitted to the Ethereum network, it needs to consume a certain amount of Gas, which will eventually be consumed by miners. 45 | 46 | Ethereum needs Gas for the following reasons: 47 | 48 | 1. Prevent DDoS attacks: The Ethereum network needs to calculate the cost of each operation, so a certain Gas fee needs to be paid when performing the operation, which can prevent malicious users from exhausting network resources through a large number of meaningless operations. 49 | 50 | 2. Network economics: Since the Ethereum network is distributed, nodes need to communicate and collaborate with each other to reach consensus. By paying Gas, the efficient use of network resources can be ensured, thereby improving the economy of the network. 51 | 52 | 3. Encourage miners: Gas fees are one of the sources of income for Ethereum miners. Since miners need to consume electricity and computing power to verify transactions and blocks, paying enough gas fees can encourage miners to verify transactions faster and pack them into blocks. 53 | 54 | 55 | 56 | ### EIP-1559 57 | 58 | From its purpose, it is a proposal to try to reduce transaction fees. 59 | 60 | In the past, the efficiency of Ethereum was indeed not high. The reason is Ethereum's "first price auction". 61 | 62 | When transactions are congested, Ethereum adopts the first-price auction principle to select transactions, in other words, "the one with the highest price wins". If 10 people bid 1 to 10 respectively, then miners will naturally choose the five transactions with bids 6 to 10 to be uploaded to the chain. 63 | 64 | 65 | 66 | ![fee1](..\pictures\fee1.png) 67 | 68 | The result is that the more congested the network is, the more users are anxious to confirm the transaction, and the higher the transaction fee paid by the user. 69 | 70 | 71 | The starting point of EIP-1559 is to change the above situation - this method is the uniform price auction. 72 | 73 | Continuing to consider the previous situation, 10 people bid 1-10 respectively, and the miners choose 5 packs. 74 | 75 | In the uniform price auction, each person who successfully goes on the chain does not need to pay his own asking price, but only needs to pay the bid of the person with the lowest bid among all the packaged transactions, and then the miners get the money as a reward. In this way, people who bid 6-10 are still packaged and uploaded to the chain, but each person only needs to pay 6. 76 | 77 | ![fee2](..\pictures\fee2.png) 78 | 79 | 80 | 81 | This proposal is naturally good for users. For them, transaction fees are reduced 82 | For miners, this auction method must be bad, because the income is significantly lower. 83 | 84 | So a miner can do this. When he finds that the price of this round of packaging is obviously too low, such as 1, he might as well generate a transaction to raise the price by himself, such as 3! 85 | When the network is already congested, these transactions generated by miners occupy the limited resources. 86 | 87 | ##### Burn base fee 88 | 89 | How to do it? 90 | 91 | In reality, there may not be many ways, but in the blockchain, there is really a way: 92 | 93 | Miners do not receive fees, but burn instead. If the handling fee needs to be destroyed, then it is not feasible for the miners to send the transaction by themselves; now sending the transaction becomes really burning their own money, and the increased handling fee will not fall into their own hands. 94 | 95 | EIP-1559 changed this handling fee to a word called basic fee. The basic fee must be destroyed. 96 | But there is also a concept of tipping at the same time. If the user is really in a hurry, you can send a tip. Tips will be received by miners. 97 | 98 | Even, this plan has another advantage, the total number of Ethereum will decrease, then the single value of Ethereum will rise in the long-term trend. 99 | 100 | But is this really the case? 101 | From the perspective of miners, they are not subordinates or hired by anyone - they are one of the most important partners of Ethereum, because they provide the most important computing power in a PoW blockchain. 102 | 103 | For miners, the base fee will be burned, so they can ask traders "unless you give us enough tips, I will not accept your transaction even if you give the base fee." 104 | 105 | [According](https://ultrasound.money/) to data from Ultra Sound Money, 7.67 ETH is burned every minute, and up to 11,042 ETH is burned each day. At current rates, approximately 4 million ETH is burned every year. However, the blockchain currently emits about 5.4 million ETH per year. -------------------------------------------------------------------------------- /ethereum/smart-contracrt.md: -------------------------------------------------------------------------------- 1 | # Smart Contract 2 | 3 | Smart contracts are one of the most important concepts of Ethereum. 4 | Bitcoin proves that data can be immutable through blockchain technology. Ethereum also puts the code on the blockchain, and has a built-in VM that can run the code. 5 | Unalterable code and data, coupled with the operating environment, means that the Ethereum provides a complete, uncontrolled, immutable computer. 6 | 7 | Imagine an Apple Store, where the app running logic is all open and will not be modified by anyone. There, in theory, we can put all the apps into this app store and re-implement it again. 8 | 9 | This is web3. 10 | 11 | 12 | 13 | ### Context 14 | 15 | "Smart contracts" are not real contracts, nor are they particularly smart, they just run code on the blockchain. 16 | 17 | Smart contracts are kept in a special kind of account on the Ethereum network. We have user accounts and can also have smart contract accounts. 18 | 19 | Smart contract accounts are: 20 | 21 | - address 22 | - Balance (how much is there: Ether) 23 | - state: The current state of all variables and variables declared in the smart contract. In fact, the easiest way to understand smart contracts can be compared to instantiating objects of a class, the only difference is that this object will always exist in the blockchain network, which is equivalent to a small database 24 | - the code 25 | 26 | Smart contracts can call other smart contracts. A smart contract typically consists of the following components: 27 | 28 | 1. Code: The code is the set of instructions that define the logic and behavior of the contract. It is written in a programming language that is compatible with the blockchain platform on which the contract is deployed. 29 | 2. State: The state is the current status of the contract, including the values of all variables and data structures used in the code. The state is updated each time the contract is executed. 30 | 3. Address: Each smart contract is assigned a unique address on the blockchain, which serves as its identifier. 31 | 4. Events: Events are messages that the contract can emit when certain conditions are met. These messages can be used to trigger other contracts or to notify external applications of important events. 32 | 5. Functions: Functions are the methods that can be called to interact with the contract. They are defined in the code and can be accessed by other contracts or by external users. 33 | 6. Gas: Gas is the fee paid by users to execute a smart contract. The amount of gas required for a transaction depends on the complexity of the code and the amount of data being processed. 34 | 35 | 36 | 37 | Let us start with a demo. 38 | 39 | ```go 40 | contract Counter { 41 | uint counter; 42 | 43 | function Counter() public { 44 | counter = 0; 45 | } 46 | function count() public { 47 | counter = counter + 1; 48 | } 49 | } 50 | ``` 51 | 52 | 53 | 54 | The code has a variable named "counter" of type uint (unsigned integer). The content (value) of the counter variable is the state of the contract. Whenever we call the count() function, the zone state of this smart contract will be incremented by 1, and this state is visible to everyone. 55 | 56 | ![contract-demo](..\pictures\contract-demo.png) 57 | 58 | 59 | 60 | Ethereum supports three types of transactions: 61 | 62 | - Transfer of value (same as Bitcoin) 63 | - TO : receiving address 64 | - DATA : leave blank or leave a message 65 | - FROM : who issued 66 | - AMOUNT : how much to send 67 | - create contract 68 | - **TO : ''''(this is what triggers the creation of the smart contract)** 69 | - DATA : Contains the smart contract code compiled to bytecode 70 | - FROM : who created 71 | - AMOUNT : Can be zero or any amount of ether, it is the deposit we want to give to the contract. 72 | - Call the contract function 73 | - TO: target contract account address 74 | - DATA: Contains the function name and parameters - identifies how to call the smart contract function 75 | - FROM : who calls 76 | - AMOUNT: Can be zero or any amount of ether, for example to pay for contract services. 77 | 78 | This also means that our call to the smart contract is achieved by creating a transaction. 79 | 80 | 81 | 82 | ### Language 83 | 84 | There are several programming languages that can be used for smart contract development on various blockchain platforms. Here are some of the most common ones: 85 | 86 | 1. **Solidity**: Solidity is the most commonly used language for developing smart contracts on the Ethereum blockchain. It is a contract-oriented language that is similar to JavaScript and is designed specifically for writing smart contracts. 87 | 2. **Vyper**: Vyper is a newer language designed to address some of the security issues with Solidity. It is also used for developing smart contracts on the Ethereum blockchain. 88 | 3. **Chaincode** (Go): Chaincode, also known as smart contracts on the Hyperledger Fabric blockchain, can be developed using Go programming language. 89 | 4. **Cadence**: Cadence is a new language developed by Dapper Labs for writing smart contracts on the Flow blockchain. 90 | 5. **Rust**: Rust is a systems programming language that can be used for writing smart contracts on the NEAR Protocol blockchain. 91 | 6. **Michelson**: Michelson is a domain-specific language designed for smart contracts on the Tezos blockchain. 92 | 93 | It's worth noting that some blockchains also support multiple programming languages for smart contract development, and new languages are constantly being developed to improve the security, efficiency, and flexibility of smart contracts. 94 | 95 | 96 | 97 | ### Smart Contract Can Do Something! 98 | 99 | Smart contracts have the potential to serve real-world use cases in many ways, including: 100 | 101 | 1. Decentralized Finance (DeFi): Smart contracts can be used to automate financial transactions, such as lending and borrowing, without the need for intermediaries. This can significantly reduce costs and increase efficiency in the financial system. 102 | 2. Supply Chain Management: Smart contracts can be used to track the movement of goods and ensure their authenticity, from the manufacturer to the end-user. This can help prevent fraud and improve transparency in supply chain management. 103 | 3. Real Estate: Smart contracts can be used to automate real estate transactions, such as property transfers and lease agreements. This can reduce the time and cost associated with traditional real estate transactions. 104 | 4. Identity Verification: Smart contracts can be used to verify the identity of individuals, which can be useful in areas such as voting, access to government services, and online transactions. 105 | 5. Gaming and Digital Collectibles: Smart contracts can be used to create digital assets, such as in-game items and collectibles, that are secured by the blockchain. This can prevent fraud and create a more transparent and secure gaming environment. 106 | 6. Insurance: Smart contracts can be used to automate insurance claims and payouts, which can reduce the time and cost associated with traditional insurance processes. 107 | 108 | Overall, smart contracts have the potential to significantly improve efficiency, transparency, and security in many different industries and use cases. As blockchain technology continues to evolve, we can expect to see more innovative applications of smart contracts in the future. 109 | 110 | Of course it's worth pointing out that these products aren't powerful enough to replace existing tools, they're just a possibility. 111 | The most important thing about Smart Contract is to lower the threshold for people to create cryptocurrency. We can conduct quick financing through ICO. 112 | 113 | 114 | 115 | ### But 116 | 117 | While smart contracts can theoretically do anything, they are not well suited for heavy computational work. 118 | 119 | The Ethereum World Computer is like an old slow computer that can run simple programs. Keeping Ethereum smart contracts small and simple is critical for cost and security reasons. 120 | 121 | The more computation a contract has, the more expensive it is to run it. The more complex the contract, the more likely it is that a security breach will occur. Security holes in smart contracts are difficult to fix because of the immutable nature of the blockchain. 122 | 123 | 124 | 125 | ### Questions 126 | 127 | - How is a smart contract library useful? 128 | - a smart contract library can be a very useful tool for smart contract developers, allowing them to save time, improve efficiency, ensure consistency, and enhance security. It can also help to promote standardization and best practices in the development of smart contracts. 129 | -------------------------------------------------------------------------------- /ethereum/erc20-token.md: -------------------------------------------------------------------------------- 1 | # ERC 20 2 | 3 | Let us try to build a homogeneous token! 4 | 5 | A homogeneous token (ERC-20) is a token created on the Ethereum (Ethereum) blockchain. Each token is exactly the same on the blockchain and has the same value and attributes. For example, if you buy 10 ERC-20 tokens, the tokens are the same, there is no difference. 6 | 7 | Non-homogeneous tokens (NFTs) are different. Each NFT is unique, unique, and has unique attributes and values. For example, a piece of digital artwork could be an NFT that has a unique design, time of creation, and artist information, attributes that set it apart from other NFTs or tokens. 8 | 9 | As another example, a real estate developer could use NFTs to represent their real estate projects. Each NFT represents a unique real estate unit with unique attributes such as location, floor area, style, design and selling price. 10 | 11 | In conclusion, fungible tokens are fungible and indistinguishable, while non-fungible tokens are unique, each with its own value and attributes. 12 | 13 | **In fact, before the launch of NFT, all tokens are homogeneous.** 14 | 15 | 16 | 17 | ```go 18 | contract ERC20Interface { 19 | 20 | string public constant name = "Token Name"; 21 | string public constant symbol = "SYM"; 22 | uint8 public constant decimals = 18; // 18 is the most common number of decimal places 23 | 24 | function totalSupply() public constant returns (uint); 25 | function balanceOf(address tokenOwner) public constant returns (uint balance); 26 | function allowance(address tokenOwner, address spender) public constant returns (uint remaining); 27 | function transfer(address to, uint tokens) public returns (bool success); 28 | function approve(address spender, uint tokens) public returns (bool success); 29 | function transferFrom(address from, address to, uint tokens) public returns (bool success); 30 | 31 | event Transfer(address indexed from, address indexed to, uint tokens); 32 | event Approval(address indexed tokenOwner, address indexed spender, uint tokens); 33 | } 34 | ``` 35 | 36 | 37 | 38 | Let us see how Tether (USDT) built by smart contract. 39 | 40 | 41 | 42 | ### Tether(USDT) 43 | 44 | Form this url https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7#code 45 | 46 | By the way, smart contracts themselves cannot be changed - once deployed to the blockchain, they are immutable. 47 | But there can be one or more smart contracts running together, some of which can act as "backends". In this way, we can upgrade the interaction mode between these smart contracts. Here, upgrading a smart contract does not mean modifying the code of a deployed smart contract, but replacing one of the smart contracts with another. We do this in such a way that (in most cases) the end user doesn't have to change how they interact with the dApp. 48 | 49 | So the real upgrading of smart contracts is a process in which new smart contracts replace old smart contracts. When the new smart contract is used, the old smart contract will be "abandoned" on the chain, because the old contract is immutable. 50 | 51 | 52 | 53 | USDT needs to have the following functions 54 | 55 | 1. Functions of transfer, balance inquiry and authorized consumption under ERC20 requirements 56 | 2. Token emergency suspension and restart 57 | 3. Token User Blacklist 58 | 4. The contract is conveniently upgraded and can be adapted to non-ERC20 protocol tokens 59 | 5. Token manager authority transfer 60 | 61 | ```solidity 62 | /** 63 | *Submitted for verification at Etherscan.io on 2017-11-28 64 | */ 65 | 66 | pragma solidity ^0.4.17; 67 | 68 | /** 69 | * @title SafeMath 70 | * @dev Math operations with safety checks that throw on error 71 | */ 72 | library SafeMath { 73 | ... 74 | } 75 | 76 | /** 77 | * @title Ownable 78 | * @dev The Ownable contract has an owner address, and provides basic authorization control 79 | * functions, this simplifies the implementation of "user permissions". 80 | */ 81 | contract Ownable { 82 | address public owner; 83 | 84 | ... 85 | 86 | /** 87 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 88 | * @param newOwner The address to transfer ownership to. 89 | */ 90 | function transferOwnership(address newOwner) public onlyOwner { 91 | if (newOwner != address(0)) { 92 | owner = newOwner; // give this contract to another account 93 | } 94 | } 95 | 96 | } 97 | 98 | /** 99 | * @title ERC20Basic 100 | * @dev Simpler version of ERC20 interface 101 | * @dev see https://github.com/ethereum/EIPs/issues/20 102 | */ 103 | contract ERC20Basic { 104 | ...; 105 | } 106 | 107 | /** 108 | * @title ERC20 interface 109 | * @dev see https://github.com/ethereum/EIPs/issues/20 110 | */ 111 | contract ERC20 is ERC20Basic { 112 | ...; 113 | } 114 | 115 | /** 116 | * @title Basic token 117 | * @dev Basic version of StandardToken, with no allowances. 118 | */ 119 | contract BasicToken is Ownable, ERC20Basic { 120 | using SafeMath for uint; 121 | 122 | mapping(address => uint) public balances; // This is balacne Db 123 | 124 | // additional variables for use if transaction fees ever became necessary 125 | uint public basisPointsRate = 0; 126 | uint public maximumFee = 0; 127 | 128 | /** 129 | * @dev Fix for the ERC20 short address attack. 130 | */ 131 | modifier onlyPayloadSize(uint size) { 132 | require(!(msg.data.length < size + 4)); 133 | _; 134 | } 135 | 136 | /** 137 | * @dev transfer token for a specified address 138 | * @param _to The address to transfer to. 139 | * @param _value The amount to be transferred. 140 | */ 141 | function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) { 142 | uint fee = (_value.mul(basisPointsRate)).div(10000); 143 | if (fee > maximumFee) { 144 | fee = maximumFee; 145 | } 146 | uint sendAmount = _value.sub(fee); 147 | balances[msg.sender] = balances[msg.sender].sub(_value); 148 | balances[_to] = balances[_to].add(sendAmount); 149 | if (fee > 0) { 150 | balances[owner] = balances[owner].add(fee); 151 | Transfer(msg.sender, owner, fee); 152 | } 153 | Transfer(msg.sender, _to, sendAmount); 154 | } 155 | 156 | /** 157 | * @dev Gets the balance of the specified address. 158 | * @param _owner The address to query the the balance of. 159 | * @return An uint representing the amount owned by the passed address. 160 | */ 161 | function balanceOf(address _owner) public constant returns (uint balance) { 162 | return balances[_owner]; 163 | } 164 | 165 | } 166 | 167 | /** 168 | * @title Standard ERC20 token 169 | * 170 | * @dev Implementation of the basic standard token. 171 | * @dev https://github.com/ethereum/EIPs/issues/20 172 | * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol 173 | */ 174 | contract StandardToken is BasicToken, ERC20 { 175 | ... 176 | } 177 | 178 | ... 179 | 180 | contract TetherToken is Pausable, StandardToken, BlackList { 181 | 182 | string public name; 183 | string public symbol; 184 | uint public decimals; 185 | address public upgradedAddress; // We use this to update Smart Contract 186 | bool public deprecated; 187 | 188 | // The contract can be initialized with a number of tokens 189 | // All the tokens are deposited to the owner address 190 | // 191 | // @param _balance Initial supply of the contract 192 | // @param _name Token Name 193 | // @param _symbol Token symbol 194 | // @param _decimals Token decimals 195 | function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public { 196 | _totalSupply = _initialSupply; 197 | name = _name; 198 | symbol = _symbol; 199 | decimals = _decimals; 200 | balances[owner] = _initialSupply; // Owner Get All Token! 201 | deprecated = false; 202 | } 203 | 204 | ... 205 | } 206 | ``` 207 | 208 | 209 | 210 | Tether claims that it will strictly abide by the 1:1 reserve guarantee. For every USDT token issued, its bank account will have 1 dollar of funds as a guarantee. 211 | 212 | We can see that Tether's smart contract has no constraints on its promises. And the smart contract of Tether currency can also be upgraded. 213 | In theory, the owner of Tether can withdraw any amount of USDT from its account to exchange for US dollars, and it will not be discovered by anyone. 214 | 215 | But we believe he won't. Because Tether has a noble and admirable moral bottom line. **Even if Tether does not have transparent financial audits and closed audits, it has never responded positively to everyone's doubts. .** -------------------------------------------------------------------------------- /ethereum/mining-start.md: -------------------------------------------------------------------------------- 1 | # Mining: Start 2 | 3 | Mining involves three channels. 4 | 5 | 1. newWorkCh 6 | 2. txsCh 7 | 3. chainSideCh 8 | 9 | ![miner-loop](..\pictures\miner-loop.png) 10 | 11 | Once we received the **newWorkCh**. We should start to mining. 12 | 13 | ```go 14 | //miner/worker.go:409 15 | case req := <-w.newWorkCh: 16 | w.commitNewWork(req.interrupt, req.noempty, req.timestamp) 17 | ``` 18 | 19 | The **txsCh** message is triggered when a new transaction is received. 20 | 21 | ```go 22 | //miner/worker.go:451 23 | case ev := <-w.txsCh: 24 | if !w.isRunning() && w.current != nil { 25 | w.mu.RLock() 26 | coinbase := w.coinbase 27 | w.mu.RUnlock() 28 | 29 | txs := make(map[common.Address]types.Transactions) 30 | for _, tx := range ev.Txs { 31 | acc, _ := types.Sender(w.current.signer, tx) 32 | txs[acc] = append(txs[acc], tx) 33 | } 34 | txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs) 35 | w.commitTransactions(txset, coinbase, nil) 36 | w.updateSnapshot() 37 | } else { 38 | if w.config.Clique != nil && w.config.Clique.Period == 0 { 39 | w.commitNewWork(nil, false, time.Now().Unix()) 40 | } 41 | } 42 | atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) 43 | ``` 44 | 45 | In the process, the new transactions will be sorted according to the price and Nonce value, and after forming an ordered transaction set, they will be committed in sequence. 46 | It can be seen that the process of receiving and processing new transactions does not interfere with mining. There is also no need to consider whether the transaction has been processed, because when the transaction is duplicated, the second committed will fail. 47 | 48 | **chainSideCh** 49 | 50 | This message is triggered when a local block is added to the side chain. After receiving this message, the block in the message (that is, the block added to the side chain) is added to the "uncle block" list, and according to the current state, two uncle blocks may be selected to submit a block generation task. (This channel is the embodiment of Ethereum encouraging uncle blocks) 51 | 52 | ```go 53 | //miner/worker.go:412 54 | case ev := <-w.chainSideCh: 55 | if _, exist := w.localUncles[ev.Block.Hash()]; exist {//❶ 56 | continue 57 | } 58 | if _, exist := w.remoteUncles[ev.Block.Hash()]; exist { 59 | continue 60 | } 61 | if w.isLocalBlock != nil && w.isLocalBlock(ev.Block) {//❷ 62 | w.localUncles[ev.Block.Hash()] = ev.Block 63 | } else { 64 | w.remoteUncles[ev.Block.Hash()] = ev.Block 65 | } 66 | if w.isRunning() && w.current != nil && w.current.uncles.Cardinality() < 2 {//❸ 67 | start := time.Now() 68 | if err := w.commitUncle(w.current, ev.Block.Header()); err == nil {//❹ 69 | var uncles []*types.Header 70 | w.current.uncles.Each(func(item interface{}) bool { 71 | //... 72 | }) 73 | w.commit(uncles, nil, true, start)//❺ 74 | } 75 | } 76 | ``` 77 | 78 | 79 | 80 | ### Set New Block Info 81 | 82 | ```go 83 | //miner/worker.go:829 84 | parent := w.chain.CurrentBlock()//Mining is to compete to dig the next block, and the block with the latest height needs to be used as the parent block 85 | 86 | if parent.Time() >= uint64(timestamp) {// Change the timestamp 87 | timestamp = int64(parent.Time() + 1) 88 | } 89 | if now := time.Now().Unix(); timestamp > now+1 { 90 | wait := time.Duration(timestamp-now) * time.Second 91 | log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait)) 92 | time.Sleep(wait) 93 | } 94 | num := parent.Number() 95 | header := &types.Header{ 96 | ParentHash: parent.Hash(), 97 | Number: num.Add(num, common.Big1), 98 | GasLimit: core.CalcGasLimit(parent, w.gasFloor, w.gasCeil), 99 | Extra: w.extra, 100 | Time: uint64(timestamp), 101 | } 102 | if w.isRunning() { 103 | if w.coinbase == (common.Address{}) { 104 | log.Error("Refusing to mine without etherbase") 105 | return 106 | } 107 | header.Coinbase = w.coinbase// Set account to get the ETH rewards 108 | } 109 | 110 | 111 | ... 112 | 113 | err := w.makeCurrent(parent, header) // Update stateDB by transaction 114 | if err != nil { 115 | log.Error("Failed to create mining context", "err", err) 116 | return 117 | } 118 | ``` 119 | 120 | ### Add Uncle Blocks 121 | 122 | We can see the code listen the chainSideCh and add a uncle blocks set. But why we need Uncle Blocks? 123 | 124 | In a distributed system, due to network delay and asynchronous communication between nodes, there is a certain delay and uncertainty. This can result in two or more miners mining a new block almost simultaneously, but only one of the blocks can be added to the blockchain. 125 | 126 | Uncle Blocks can motivate more miners to participate in the consensus process, even if their blocks are not confirmed and added to the main chain. 127 | 128 | 129 | 130 | ### PoW find Nonce 131 | 132 | ```go 133 | //miner/worker.go:508 134 | case task := <-w.taskCh: 135 | //... 136 | sealHash := w.engine.SealHash(task.block.Header())//get the hash of block 137 | if sealHash == prev { 138 | continue 139 | } 140 | interrupt() 141 | stopCh, prev = make(chan struct{}), sealHash 142 | 143 | if w.skipSealHook != nil && w.skipSealHook(task) { 144 | continue 145 | } 146 | w.pendingMu.Lock() 147 | w.pendingTasks[w.engine.SealHash(task.block.Header())] = task 148 | w.pendingMu.Unlock() 149 | 150 | if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil { // find nonce and send resultCh 151 | log.Warn("Block sealing failed", "err", err) 152 | } 153 | 154 | //miner/worker.go:542 155 | select { 156 | case block := <-w.resultCh: 157 | if block == nil { 158 | continue 159 | 160 | if w.chain.HasBlock(block.Hash(), block.NumberU64()) { 161 | continue 162 | } 163 | var ( 164 | sealhash = w.engine.SealHash(block.Header()) 165 | hash = block.Hash() 166 | ) 167 | ``` 168 | 169 | 170 | 171 | Finally, Broadcast the new Block. 172 | 173 | ```go 174 | //eth/handler.go:771 175 | func (pm *ProtocolManager) minedBroadcastLoop() { 176 | for obj := range pm.minedBlockSub.Chan() { 177 | if ev, ok := obj.Data.(core.NewMinedBlockEvent); ok { 178 | pm.BroadcastBlock(ev.Block, true) //❼ 179 | pm.BroadcastBlock(ev.Block, false) //❽ 180 | } 181 | } 182 | } 183 | ``` 184 | 185 | 186 | 187 | ![mining-process](..\pictures\mining-process.png) 188 | 189 | 190 | 191 | 192 | 193 | ### One more thing: How to use GPU to mining? 194 | 195 | Ethereum uses a hashing algorithm called Ethash, which is a memory-hard algorithm, meaning it requires a lot of memory to mine efficiently. The purpose of this algorithm design is to avoid the emergence of ASIC (application-specific integrated circuit) mining machines, so that ordinary computers can also have the opportunity to participate in mining. 196 | 197 | CPUs usually only have smaller caches, while GPUs have larger memory and higher memory bandwidth, which makes GPUs more suitable for the memory-intensive calculations required in the Ethash algorithm. In contrast, the performance of CPUs is mainly determined by the clock speed and computing power of individual cores, and their memory bandwidth is relatively small. 198 | 199 | Therefore, using GPU mining is more efficient than using CPU mining, and it is also the current mainstream method of Ethereum mining. 200 | 201 | The basic principle of the Ethash algorithm is to use a data structure called DAG (Directed Acyclic Graph) for hash calculation. This DAG is computed iteratively as a series of hash functions, each of which depends on the results of previous hash functions. Therefore, the calculation of DAG is a very memory-intensive process. 202 | 203 | Specifically, the Ethash algorithm first generates a 256MB DAG using a random number called a "hash seed". Miners then need to perform hash calculations using the DAG and some other data such as mining parameters and Nonce to find eligible blocks. Each calculation process needs to use some random data in the DAG, which needs to be stored in memory. Since the DAG is very large, a lot of memory is required to store it. The greater the amount of memory used by the miner, the faster the calculations because more data can be cached. 204 | 205 | In addition, the Ethash algorithm also designs a data structure called "cache" to speed up hash calculations. The size of the cache is determined by the hardware of the miner. A larger cache means that the miner can calculate the correct hash value faster, thus achieving higher mining efficiency. 206 | 207 | The reason why a lot of memory is needed is because the Ethash algorithm uses the DAG data structure for hash calculations, and the DAG is very large and requires a lot of memory to store it. Since miners need to frequently use DAG for hash calculations, a large amount of memory is required to cache these data, thereby improving computing efficiency. 208 | 209 | The RTX 3090, for example, has 24 GB of GDDR6X memory. -------------------------------------------------------------------------------- /ethereum/transaction.md: -------------------------------------------------------------------------------- 1 | # Transaction 2 | 3 | The complete process of an Ethereum transaction is divided into the following steps: 4 | 5 | 1. Initiate a transaction: specify the target address and transaction amount, as well as the required gas/gaslimit 6 | 2. Transaction signature: use the account private key to sign the transaction 7 | 3. Submit the transaction: add the transaction to the transaction buffer pool txpool (the transaction signature will be verified first) 8 | 4. Broadcast transaction: notify EVM to execute, and broadcast transaction information to other nodes at the same time 9 | 10 | 11 | 12 | ### Initiate a transaction 13 | 14 | The code in internal/ethapi/api.go. 15 | 16 | ```go 17 | func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args SendTxArgs) (common.Hash, error) { 18 | 19 | // Look up the wallet containing the requested signer 20 | account := accounts.Account{Address: args.From} 21 | 22 | wallet, err := s.b.AccountManager().Find(account) 23 | if err != nil { 24 | return common.Hash{}, err 25 | } 26 | 27 | if args.Nonce == nil { 28 | // Hold the addresse's mutex around signing to prevent concurrent assignment of 29 | // the same nonce to multiple accounts. 30 | s.nonceLock.LockAddr(args.From) 31 | defer s.nonceLock.UnlockAddr(args.From) 32 | } 33 | 34 | // Set some sanity defaults and terminate on failure 35 | if err := args.setDefaults(ctx, s.b); err != nil { 36 | return common.Hash{}, err 37 | } 38 | // Assemble the transaction and sign with the wallet 39 | tx := args.toTransaction() 40 | 41 | var chainID *big.Int 42 | if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) { 43 | chainID = config.ChainId 44 | } 45 | signed, err := wallet.SignTx(account, tx, chainID) 46 | if err != nil { 47 | return common.Hash{}, err 48 | } 49 | return submitTransaction(ctx, s.b, signed) 50 | } 51 | 52 | func (args *SendTxArgs) toTransaction() *types.Transaction { 53 | var input []byte 54 | if args.Data != nil { 55 | input = *args.Data 56 | } else if args.Input != nil { 57 | input = *args.Input 58 | } 59 | if args.To == nil { 60 | return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input) 61 | } 62 | return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input) 63 | } 64 | 65 | type txdata struct { 66 | AccountNonce uint64 `json:"nonce" gencodec:"required"` 67 | Price *big.Int `json:"gasPrice" gencodec:"required"` 68 | GasLimit uint64 `json:"gas" gencodec:"required"` 69 | Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation 70 | Amount *big.Int `json:"value" gencodec:"required"` 71 | Payload []byte `json:"input" gencodec:"required"` 72 | 73 | // Signature values 74 | V *big.Int `json:"v" gencodec:"required"` 75 | R *big.Int `json:"r" gencodec:"required"` 76 | S *big.Int `json:"s" gencodec:"required"` 77 | 78 | // This is only used when marshaling to JSON. 79 | Hash *common.Hash `json:"hash" rlp:"-"` 80 | } 81 | ``` 82 | 83 | 84 | 85 | ### Transaction signature 86 | 87 | TxData calculates the hash value of transaction data through the Keccak-256 algorithm, and then combines the private key of the account to generate signature data through ECDSA (Elliptic Curve Digital Signature Algorithm), which is the elliptic curve digital signature algorithm. 88 | 89 | Of course, we can also send the private key to others for direct verification. But in this case, our account has no security at all. Once the private key is exposed, our account balance will be quickly removed. 90 | 91 | 92 | 93 | #### Keccak-256 94 | 95 | Keccak-256 algorithm is a hash function defined in the SHA-3 standard, which is a member of the Keccak hash function family designed by Guido Bertoni, Joan Daemen, Michaël Peeters, and Gilles Van Assche. The algorithm is based on the Keccak-f permutation function and uses the SPONGE construction method to compute the hash of any input data with a fixed output length of 256 bits. 96 | 97 | The specific steps of the Keccak-256 algorithm are as follows: 98 | 99 | 1. Padding the data 100 | 101 | First, the input data is padded to a length that is a multiple of 136 bytes. The padding rules are as follows: 102 | 103 | - Append a binary 1 to the end of the data. 104 | - Append several binary 0s to the end of the data to make the length a multiple of 136 bytes. 105 | - Append a 32-bit binary integer to the end of the padded data to represent the length of the original data (in bits). 106 | 107 | 1. Computing the hash 108 | 109 | Divide the padded data into several 136-byte blocks and compute the hash of each block. The hash calculation process includes the following steps: 110 | 111 | - Divide each block into 17 8-byte slices called "states". 112 | - Perform a series of permutation operations on the states, called the Keccak-f permutation function. 113 | - Repeat the permutation operation on each block until all blocks have been processed. 114 | 115 | 1. Output the hash value 116 | 117 | The state of the last block is used as the output hash value. 118 | 119 | The Keccak-256 algorithm is relatively simple, but it uses advanced techniques to enhance security, making it effective against various attacks. 120 | 121 | 122 | 123 | ### ECDSA 124 | 125 | 126 | 127 | Then let's see how this value pair is created for signing: 128 | 129 | 1. generate a random number k 130 | 2. Calculate using dot multiplication p = k * G 131 | 3. R = xP, hash of txData is z 132 | 4. mod p 133 | 134 | 135 | 136 | So, the sender should send R, S, PubKey, in header, and txData in Body. 137 | 138 | The receiver can check if the sign is correct. 139 | 140 | The receiver just do this. 141 | 142 | P = S ^ -1 * z * G + S^-1 * R * PubKey 143 | 144 | if xP = R, the data is correct. In this way, a verification is completed without exposing the private key. 145 | 146 | We can prove this. 147 | 148 | ```go 149 | P = S ^ -1 * z * G + S^-1 * R * PubKey 150 | //PubKey = privKey * G, so 151 | P = S ^ -1 * z * G + S^-1 * R * privKey * G 152 | P = S ^ -1 * z * G + S^-1 * R * privKey * G 153 | P = S ^ -1 * G * ( z + R * privKey) 154 | // if P is a point in ECC, there must be some K make P = K * G, so 155 | K * G = S ^ -1 * G * ( z + R * privKey) 156 | K = S ^ -1 * ( z + R * privKey) 157 | 158 | 159 | // And we know how sender create S. 160 | S = k ^ -1( z + privKey * R) 161 | k = S ^ -1 * ( z + R * privKey) 162 | 163 | So, k = K 164 | ``` 165 | 166 | 167 | 168 | ### Questions 169 | 170 | - Can you explain the difference between on chain and off chain transactions in web3? 171 | 172 | - On-chain transactions refer to transactions that are recorded and executed directly on the blockchain. These transactions involve sending or receiving cryptocurrency or tokens, executing smart contracts, and updating the state of the blockchain. On-chain transactions require gas fees to be paid in order to incentivize miners to validate and process the transaction. Once a transaction is processed and confirmed by the network, it is permanently recorded on the blockchain and can be viewed by anyone. 173 | 174 | Off-chain transactions, on the other hand, refer to transactions that occur outside of the blockchain, but are still related to the blockchain. These transactions can include transferring cryptocurrency or tokens between two parties using an off-chain payment channel, such as the Lightning Network, which allows for instant and low-cost transactions. Off-chain transactions can also include any interactions between two or more parties that do not involve updating the state of the blockchain. Off-chain transactions do not require gas fees and can occur instantly without the need for confirmation by the network. 175 | 176 | In summary, on-chain transactions involve interacting directly with the blockchain and updating its state, while off-chain transactions occur outside of the blockchain and can involve various forms of payment channels or other interactions between parties. Both types of transactions have their advantages and disadvantages, and their suitability depends on the specific use case and requirements. 177 | 178 | - Can you "hide" a transaction in Ethereum? 179 | 180 | - In Ethereum, you cannot truly "hide" a transaction because Ethereum's transaction records are public and can be viewed by anyone. However, there are some techniques that can obscure the traceability of a transaction, making it more difficult to discover. 181 | 182 | One method is to use smart contracts to proxy the transaction. This method can hide the sender and receiver of the transaction behind the smart contract, making the transaction appear to be sent by the contract itself rather than the actual sender. However, this method still leaves a record of the contract transaction, so it is still traceable. 183 | 184 | Another method is to use cryptocurrency mixers. These services mix a user's cryptocurrency with other users' cryptocurrency to make it more difficult to trace the sender and receiver of each specific transaction. However, this method can still be traceable as the mixer service may leave some traces in the transaction. 185 | 186 | In summary, while transactions cannot truly be "hidden" in Ethereum, there are techniques that can be used to increase transaction privacy and security. However, it should be noted that these methods may not be entirely reliable and have some risks and vulnerabilities, so they should be used with caution. 187 | 188 | - What tools are needed to sign a transaction? 189 | 190 | - Private Key 191 | -------------------------------------------------------------------------------- /ethereum/zero-knowledge-proof.md: -------------------------------------------------------------------------------- 1 | # Zero Knowledge Proof and zk-SNARK 2 | 3 | Here's the classic example given in every complexity course I've taken: 4 | Let's say your friend is colorblind. 5 | 6 | 1. You have two billiard balls; one is red and one is green, but they are otherwise identical. 7 | 2. To your friend they look identical and he doubts they can really be distinguished. 8 | 3. You want to prove to him that they are actually different colors. 9 | 4. On the other hand, you don't want him to know which is red and which is green. 10 | 11 | This is the proof system. 12 | 13 | 1. You give your friend two balls to hold one in each hand. 14 | 2. At this point you can see the ball, but you don't tell him which is which. 15 | 3. Then your friend puts his hands behind his back. Next, he either switches the balls between the hands or leaves them as they are, with probability 1/2 for each hand. Finally, he brought them out from behind. 16 | 4. You now have to "guess" if he switched the ball. 17 | 18 | You can of course say for sure if he replaced them by looking at their color. 19 | On the other hand, if they are the same color and are therefore indistinguishable, then it is impossible for you to guess correctly with a probability higher than 1/2. 20 | 21 | If you and your friend repeat this "proof" 10000 times, your friend should be confident that the balls are indeed different colors; otherwise, your probability of successfully identifying all switches/non-switches is at most 2^(−10000). 22 | 23 | Also, the proof is "zero-knowledge" because your friend will never know which ball is green and which is red; 24 | In fact, he knew nothing about how to distinguish the balls. 25 | 26 | 27 | 28 | ### zk-SNARK 29 | 30 | Around 2013, ZK-SNARKs (Zero-Knowledge Succinct Non-Interactive Argument of Knowledge), an algorithm for constructing digital signatures based on interactive zero-knowledge proofs, was practically feasible and implemented, and actually used in applications. 31 | 32 | 33 | 34 | Zcash is the first widespread application of zk-SNARKs, a novel form of zero-knowledge cryptography. Zcash's strong privacy guarantees stem from the fact that shielded transactions in Zcash can be fully encrypted on the blockchain, yet still verifiable under the network's consensus rules by using zk-SNARK proofs. 35 | 36 | The acronym zk-SNARK stands for "Zero-Knowledge Succinct Non-Interactive Argument of Knowledge" and refers to a proof structure in which one can prove possession of certain information, such as a secret key, while There is no need to reveal that information, and there is no interaction between prover and verifier. 37 | 38 | 39 | 40 | Zcash is the first widespread application of zk-SNARKs. Zcash's strong privacy guarantees stem from the fact that shielded transactions in Zcash can be fully encrypted on the blockchain, yet still verifiable under the network's consensus rules by using zk-SNARK proofs. 41 | 42 | **One can prove possession of certain information, such as a private key, without revealing that information, and without any interaction between the prover and the verifier.** 43 | 44 | "Zero-knowledge" proofs allow one party (the prover) to prove to another party (the verifier) that a statement is true without revealing any information beyond the validity of the statement itself. For example, given a hash of a random number, a prover can convince a verifier that there is indeed a number with that hash value, and that the prover really knows that number, without revealing what it is. 45 | 46 | "Succinct" zero-knowledge proofs can be verified in milliseconds, even for statements about very large programs, and the proof length is only a few hundred bytes. In a "non-interactive" structure, a proof consists of a single message sent from the prover to the verifier. 47 | 48 | Define V to represent the verifier, P to represent the prover, F(x), M(x) are polynomial functions, and the highest order is K 49 | 50 | 51 | 52 | ##### Polynomial Zero Problem 53 | 54 | Suppose V has a function F(x) and P has a function M(x). P tries to prove that P knows F(x), ie M(x) = F(x) 55 | 56 | Then first, P asks V to give it a random number a, and then P returns the value of M(a) to V. 57 | 58 | V calculates F(a) == M(a). 59 | 60 | This is because the zeros of the polynomial are finite and at most the order K of the equation. If M(x) recognized by P is not F(x). Then g(x) = F(x) - M(x) with only not many and K zeros. V is a value a randomly selected within the range of real numbers, which just satisfies g(a), and the probability of wrong judgment of V is extremely low. 61 | 62 | In fact, V can repeat this operation 100 times. If these 100 P times give correct results, it is almost certain that P really knows F(x), that is, M(x) = F(x). 63 | 64 | If P really doesn't know F(x), it is guessing, and the difficulty of guessing will even increase rapidly with the increase of K. 65 | 66 | 67 | 68 | ##### Digital Encryption 69 | 70 | Choose a base number, such as 5, if we want to encrypt 3, the encryption method is 5^3= 125 71 | 72 | Define the encryption function as E(v) = g^v mod n, where v is the number we need to encrypt. Obviously, if one obtains E(a) in a transmission, it is almost impossible for that person to deduce what a actually is. 73 | 74 | What are the advantages of this function? 75 | 76 | 77 | 78 | Suppose V knows F(x) = x^3 + x^2 + x, which can be expressed as (1, 1, 0 ) base g. 79 | 80 | P tries to prove that he knows the equation. 81 | 82 | Then V generates a random number a, and will send a set of numbers to P A0 = ga, A1 = ga2, A2 = g< sup>a3 83 | 84 | P performs the following operations. 85 | 86 | result = A0 * A1 * A2 = ga * ga2 * ga3 = ga3+ a2+a 87 | 88 | P just send the result back. 89 | 90 | 91 | 92 | After V receives the result and knows g and a, he can quickly verify the result. 93 | 94 | 95 | 96 | In this process, 97 | 98 | V did not expose g, a. 99 | 100 | It is difficult for P to guess the result without knowing F(x). 101 | 102 | 103 | 104 | ##### Restricting a Polynomial 105 | 106 | Notice! 107 | 108 | As V, our real expectation is that P use the A0 = ga sent by me, A1 = ga2, A2 = ga3, with polynomial coefficients for calculation. 109 | 110 | But if there is a fake FP, it can hold the coefficient of g (initiate a random request first), such as B0 = gb, B1 = gb2, B2 = gb3 111 | 112 | Then use these numbers to violently piece together the result. 113 | 114 | 115 | 116 | To solve this problem, we introduce Knowledge-of-Exponent Assumption” (KEA) 117 | 118 | V first generates a random number r and an offset a, and sends two sets of data to P. 119 | 120 | A0 = gr, A1 = gr2, A2 = gr3 121 | 122 | B0 = gar, B1 = gar2, B2 = gar3 123 | 124 | 125 | 126 | P must count the two groups at the same time. 127 | 128 | 129 | 130 | So far, we have solved zero-knowledge. Obviously, it is completely impossible for P to gain any knowledge from the data given by V. 131 | 132 | Why do we even need to have non-interactive? 133 | 134 | Because the interactive proof is only valid for the original verifier V, no one else (other verifiers) can trust this proof, 135 | 136 | Obviously, V can tell P about r and a. P can happily generate these fake data. The other V's certainly can't trust P's credibility. 137 | 138 | Instead, each V requires P to interact with itself. 139 | 140 | 141 | 142 | Use the elliptic curve to realize the following function, which satisfies the definition 143 | 144 | e(ga , gb ) = e(gb , ga ) = e(gab, g1 ) = e(g1 ,gab)) = e(g1 , ga )b = e(g1 , g1 ) ab 145 | 146 | 147 | 148 | We let an honest party generate secret values r and α. Once α and all necessary powers of r and their corresponding α offsets are generated and encrypted, the original data must be deleted. Call it common reference string or CRS 149 | 150 | (ga, gri , gari , r = 0 1,..., d ). 151 | 152 | 153 | 154 | Among them, V needs to send gri , gari to P. 155 | 156 | P returns the calculation result to V according to the function coefficients it knows. 157 | 158 | V uses (ga, gri ) verification. 159 | 160 | 161 | 162 | Of course, if all nodes generate r and a continuously in the actual environment, this is the setup process. 163 | 164 | Generally speaking, we don't need to prove "whether someone knows a polynomial", but "whether someone knows a secret value, which satisfies certain conditions (such as the hash value x)". So how to turn the problem of "does someone know a secret value, which satisfies certain conditions" into a question of "does someone know a polynomial"? 165 | 166 | We can write a program to check whether this value satisfies the condition. If it is satisfied, it will output 1, and if it is not satisfied, it will output 0. And through some methods that people have developed, the program can be converted into a circuit, and the input and output of the circuit are the program. Input-Output (P(x) = A(x)B(x)-C(x)). And the circuit can be converted into a polynomial with a specific zero root (the coefficients of the polynomial are related to each input and output of the circuit). 167 | 168 | 169 | 170 | ### ZK Rollups 171 | 172 | Rollup is a scaling solution that executes transactions outside L1 but publishes transaction data on L1. This way of working allows rollups to expand the network while still being securely protected by the Ethereum consensus. Moving computation off-chain can actually process more transactions. Because only some data of the rollup transaction needs to be put into the Ethereum block. 173 | 174 | After executing the transactions on the rollup, the next step is to package these transactions into a batch and publish it to the Ethereum main chain. The whole process is basically executing transactions, extracting data, compressing them, rolling them into batches and sending them to the main chain, hence the name - "rollup". 175 | 176 | How does Ethereum know that this data is valid and not submitted by malicious actors for profit? Each rollup deploys a set of smart contracts in L1 to process deposits, withdrawals, and verify proofs. Proof is also the main factor that differentiates the different types of rollups. 177 | 178 | 179 | In ZK rollups, each batch published to L1 contains a cryptographic proof called a ZK-SNARK. After the transaction batch is submitted to L1, the contract on L1 can quickly verify the ZK-SNARK proof, and invalid batches will be directly rejected. 180 | -------------------------------------------------------------------------------- /ethereum/evm.md: -------------------------------------------------------------------------------- 1 | # EVM 2 | 3 | Usually, the development process of a smart contract is to use solidity to write logic code, compile it into bytecode through a compiler, and then publish it on Ethereum. The bottom layer of Ethereum supports the execution and calling of contracts through the EVM module. When calling, the code is obtained according to the contract address, that is, The bytecode of the contract is loaded into the EVM for execution after the environment is generated. 4 | 5 | The general flow is as shown in Figure 1. The execution process of the instructions is shown in Figure 2. The instructions are continuously fetched from the EVM code for execution, using Gas to realize the limit cycle, using the stack for operations, storing temporary variables in the memory, and storing data in the account state. . 6 | 7 | EVM distinguishes between temporary storage (Memory, which exists in each VM instance and disappears after the execution of the VM) and permanent storage (Storage, which exists in the state layer of the blockchain). 8 | 9 | 10 | 11 | ![evm_process](..\pictures\evm_process.jpg) 12 | 13 | 14 | 15 | ![evm_process](..\pictures\evm_code_executed.png) 16 | 17 | 18 | 19 | 20 | 21 | ### Code 22 | 23 | ```go 24 | type Context struct { 25 | CanTransfer CanTransferFunc 26 | Transfer TransferFunc 27 | GetHash GetHashFunc 28 | Origin common.Address 29 | GasPrice *big.Int 30 | Coinbase common.Address 31 | GasLimit uint64 32 | BlockNumber *big.Int 33 | Time *big.Int 34 | Difficulty *big.Int 35 | } 36 | 37 | type EVM struct { 38 | Context 39 | StateDB StateDB 40 | depth int 41 | chainConfig *params.ChainConfig 42 | chainRules params.Rules 43 | vmConfig Config 44 | interpreter *Interpreter 45 | abort int32 46 | callGasTemp uint64 47 | } 48 | 49 | // create Contract 50 | func (evm *EVM) create(caller ContractRef, code []byte, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { 51 | if evm.depth > int(params.CallCreateDepth) { // less then 1024 52 | return nil, common.Address{}, gas, ErrDepth 53 | } 54 | if !evm.CanTransfer(evm.StateDB, caller.Address(), value) { // Check account balance 55 | return nil, common.Address{}, gas, ErrInsufficientBalance 56 | } 57 | nonce := evm.StateDB.GetNonce(caller.Address()) 58 | evm.StateDB.SetNonce(caller.Address(), nonce+1) 59 | 60 | contractHash := evm.StateDB.GetCodeHash(address) 61 | if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) { 62 | return nil, common.Address{}, 0, ErrContractAddressCollision 63 | } 64 | 65 | snapshot := evm.StateDB.Snapshot() 66 | evm.StateDB.CreateAccount(address) 67 | if evm.ChainConfig().IsEIP158(evm.BlockNumber) { 68 | evm.StateDB.SetNonce(address, 1) 69 | } 70 | evm.Transfer(evm.StateDB, caller.Address(), address, value) 71 | 72 | contract := NewContract(caller, AccountRef(address), value, gas) 73 | contract.SetCallCode(&address, crypto.Keccak256Hash(code), code) 74 | 75 | if evm.vmConfig.NoRecursion && evm.depth > 0 { 76 | return nil, address, gas, nil 77 | } 78 | 79 | if evm.vmConfig.Debug && evm.depth == 0 { 80 | evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, code, gas, value) 81 | } 82 | start := time.Now() 83 | 84 | ret, err := run(evm, contract, nil) 85 | 86 | maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize 87 | 88 | if err == nil && !maxCodeSizeExceeded { 89 | createDataGas := uint64(len(ret)) * params.CreateDataGas 90 | if contract.UseGas(createDataGas) { 91 | evm.StateDB.SetCode(address, ret) 92 | } else { 93 | err = ErrCodeStoreOutOfGas 94 | } 95 | } 96 | 97 | if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) { 98 | evm.StateDB.RevertToSnapshot(snapshot) 99 | if err != errExecutionReverted { 100 | contract.UseGas(contract.Gas) 101 | } 102 | } 103 | 104 | if maxCodeSizeExceeded && err == nil { 105 | err = errMaxCodeSizeExceeded 106 | } 107 | if evm.vmConfig.Debug && evm.depth == 0 { 108 | evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) 109 | } 110 | return ret, address, contract.Gas, err 111 | 112 | } 113 | ``` 114 | 115 | 116 | 117 | First, a series of verifications will be performed, 118 | 119 | 1. The depth of the call stack cannot exceed 1024; 120 | 2. The called account has enough balance; 121 | 3. Initiate a transfer operation, subtract the value from the sender’s address balance, add the value to the balance of the contract account, and then call SetCallCode of the contract to initialize the contract according to the sender’s address, contract address, amount value, gas, contract code, and code hash Object, and then call run(evm, contract, nil) to execute the initialization code of the contract. The generated code has a certain length limit. When the contract is successfully created and no error is returned, the gas required to store the code is calculated. 122 | 123 | It can be seen that the contract code is stored in the storage area pointed to by the codehash in the account through the SetCode of the state module. This part of the code belongs to the modification of the world state. 124 | 125 | The fund transfer of the Create method occurs between the creating contract user account and the contract account 126 | 127 | 128 | 129 | ### Call 130 | 131 | When transferring money or executing contract code, the Call method will be called, and the call instruction in the contract will also call this method. 132 | 133 | 134 | 135 | ```go 136 | func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { 137 | if evm.vmConfig.NoRecursion && evm.depth > 0 { 138 | return nil, gas, nil 139 | } 140 | 141 | if evm.depth > int(params.CallCreateDepth) { 142 | return nil, gas, ErrDepth 143 | } 144 | if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) { 145 | return nil, gas, ErrInsufficientBalance 146 | } 147 | 148 | var ( 149 | to = AccountRef(addr) 150 | snapshot = evm.StateDB.Snapshot() 151 | ) 152 | if !evm.StateDB.Exist(addr) { 153 | precompiles := PrecompiledContractsHomestead 154 | if evm.ChainConfig().IsByzantium(evm.BlockNumber) { 155 | precompiles = PrecompiledContractsByzantium 156 | } 157 | if precompiles[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { 158 | if evm.vmConfig.Debug && evm.depth == 0 { 159 | evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) 160 | evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil) 161 | } 162 | return nil, gas, nil 163 | } 164 | evm.StateDB.CreateAccount(addr) 165 | } 166 | evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) 167 | 168 | contract := NewContract(caller, to, value, gas) 169 | contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) 170 | 171 | start := time.Now() 172 | 173 | if evm.vmConfig.Debug && evm.depth == 0 { 174 | evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) 175 | 176 | defer func() { 177 | evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) 178 | }() 179 | } 180 | ret, err = run(evm, contract, input) // run the code for smart contract 181 | 182 | if err != nil { 183 | evm.StateDB.RevertToSnapshot(snapshot) 184 | if err != errExecutionReverted { 185 | contract.UseGas(contract.Gas) 186 | } 187 | } 188 | return ret, contract.Gas, err 189 | } 190 | 191 | func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) { //The Run method will execute the code of the contract in a loop, 192 | if contract.CodeAddr != nil { 193 | precompiles := PrecompiledContractsHomestead 194 | if evm.ChainConfig().IsByzantium(evm.BlockNumber) { 195 | precompiles = PrecompiledContractsByzantium 196 | } 197 | if p := precompiles[*contract.CodeAddr]; p != nil { 198 | return RunPrecompiledContract(p, input, contract) 199 | } 200 | } 201 | return evm.interpreter.Run(contract, input) 202 | } 203 | ``` 204 | 205 | 206 | 207 | ### Gas for execute a call 208 | 209 | In order to optimize the execution efficiency of smart contracts and reduce Gas costs, the following measures can be taken: 210 | 211 | 1. Simplify the logic and code of smart contracts and reduce the computing resources required for execution. 212 | 213 | 2. Use Solidity to write efficient smart contract code, such as using appropriate data types and algorithms, and avoiding expensive operations such as loops and recursion. 214 | 215 | 3. 216 | Reduce the number of smart contract interactions and avoid frequent calls to other smart contracts and external services, thereby reducing the gas cost of the interaction. 217 | 218 | 4. Use Gas optimization tools, such as Solidity's gas() function, Remix, etc., to analyze the Gas consumption of smart contracts and further optimize the smart contract code. 219 | 220 | 221 | 222 | ### Questions 223 | 224 | - What are the components of the Ethereum Virtual Machine? What are the parts of the memory of the Ethereum virtual machine? 225 | - Stack: The stack is a data structure that stores values during the execution of a program. The EVM uses a stack-based architecture, which means that all operations are performed on the stack. 226 | - Memory: The memory is a linear array of bytes that can be used by a program to store data during execution. The memory is volatile, which means that it is cleared when the program terminates. 227 | - Storage: The storage is a persistent key-value store that is used to store data between transactions. The storage is backed by the blockchain, which means that it is immutable. 228 | - Please explain Storage, which variables are stored? . 229 | - Storage is a persistent key-value store that is used to store data between transactions. Variables that are stored in storage are persistent across multiple executions of a smart contract. In Solidity, variables declared with the "storage" keyword are stored in storage. 230 | - Please explain the memory (Memory), which variables are stored? 231 | - Memory is a linear array of bytes that can be used by a program to store data during execution. Unlike storage, the memory is volatile, which means that it is cleared when the program terminates. Variables that are stored in memory are not persistent across multiple executions of a smart contract. In Solidity, variables declared with the "memory" keyword are stored in memory. 232 | - Please explain Calldata. 233 | - Calldata is a read-only area of memory that contains the input data for a function call. When a function is called in a smart contract, the input data is passed to the function via the calldata. The calldata is immutable, which means that it cannot be modified by the function. 234 | - What is the difference between EVM calls and non-EVM calls? 235 | - EVM calls are function calls that are executed within the Ethereum Virtual Machine. EVM calls are used to call functions within a smart contract or to call other smart contracts. Non-EVM calls are function calls that are executed outside of the Ethereum Virtual Machine. Non-EVM calls are used to interact with external systems, such as APIs or databases. EVM calls are more expensive than non-EVM calls because they require more computation and are executed within the context of the Ethereum blockchain. -------------------------------------------------------------------------------- /ethereum/mining-chainconfig.md: -------------------------------------------------------------------------------- 1 | # Mining:ChainConfig 2 | 3 | Mining is the process of encapsulating a series of recent unencapsulated transactions into a new block. 4 | 5 | Let us start with some context. 6 | 7 | 8 | 9 | ### Byzantine generals problem 10 | 11 | The state synchronization problem of distributed systems. Each node in a distributed system is a general, and when these nodes want to synchronize their state, they will face the Byzantine general problem. 12 | 13 | > The Byzantine Empire was prosperous, and the generals of several small countries around it coveted it for a long time, but each had their own secrets. More than half of their generals must agree to attack Byzantium and cannot betray on the battlefield (reach a consensus), otherwise the attack will fail and burn themselves. And the general's territory may be divided up by several other generals. Based on this situation, the communication among the generals is very problematic. Some people have duplicity, and some people are loyal to the interests of the organization. How to finally reach a consensus is a problem. 14 | 15 | #### POW(Proof Of Work) 16 | 17 | In order to solve the Byzantine general problem, we need to determine a method first: 18 | 19 | Select a loyal "general" from among these equal generals, and the other generals can just listen to his decision. 20 | 21 | > This seems to violate the idea of decentralization, but after careful analysis, these generals are decentralized equal nodes before making this decision, and the selected generals are only for this decision. Decided to choose again. Instead of a centralized and permanently fixed general. 22 | 23 | How to choose a general? 24 | These generals are equal nodes, so we asked them to give a statement on this decision. Generals need to calculate based on known battlefield information, try to draw conclusions (blocks), and then broadcast the conclusions to other generals. If his conclusions are recognized by most generals, then he is the general of this round. 25 | At the same time, the general must always monitor the broadcast content from other generals. Once the conclusion broadcast from other generals is received, the generals will immediately stop the calculations in their hands to verify the content of the broadcast. If all the generals pass the verification, then the first The first general who broadcasts this verifiable result is selected as a general, and this time he decided to listen to his conclusion. 26 | 27 | So there are two important factors in this process: 28 | 29 | 1. The first is speed, the first one who passes the verification can be selected as a general, and the second one who is a step slower has no chance. The problem of speed is the problem of computing power. For example, the computing power of an 8-core 32G computer is definitely faster than that of a single-core 1G. 30 | 31 | 2. Then there is correctness, that is, whether the conclusion issued by the general is correct or not, and needs to be verified successfully by other generals. 32 | 33 | POW provides a way that is difficult to calculate and easy to verify, which is realized based on the characteristics of the hash function. 34 | 35 | A hash encryption function can be issued to each node, and each node calculates an encrypted hash by adding a nonce value to the block information to be sealed. This encrypted hash needs to meet certain rules (such as the first four bits must be 1111) 36 | The workload refers to the workload that the node is constantly trying to calculate. After obtaining the eligible block hash, after broadcasting, the ongoing and completed workload of other nodes will be invalidated (in fact, this is also a kind of computing power. waste), this is the block. 37 | 38 | 39 | 40 | This way is not prefect. 41 | 42 | ##### Question 1: 43 | 44 | What if two nodes produce blocks with the same content at the same time? 45 | 46 | Compare timestamps. The one with an earlier time will be confirmed and kept on-chain, while the one with a later time will be discarded. 47 | 48 | ##### Question 2: Fork 49 | 50 | If a node publishes a new consensus rule, other nodes do not synchronize the consensus rule? 51 | Nodes that have not synchronized the new rules will continue to mine, and the blocks they dig will not be consensus or recognized by the nodes of the new rules. At this time, the chain is forked and divided into two chains, 1.0 (old consensus rules) and 2.0 (new consensus rules). At this point chains with a larger mass (miner) base will stay. 52 | 53 | Of course, some people still use the original 1.0 chain, but its vitality is definitely gone, because **no one will do it for nothing**. 54 | 55 | 56 | 57 | ### Source code for Miner 58 | 59 | Here is the UML for mining. 60 | 61 | ![miner-uml](..\pictures\miner-uml.png) 62 | 63 | Here is the code. 64 | 65 | ```go 66 | type Miner struct { 67 | mux *event.TypeMux // Mux 68 | worker *worker 69 | coinbase common.Address 70 | mining int32 // mining status 71 | eth Backend // Backend 72 | engine consensus.Engine //ethash, clique。 73 | canStart int32 // Can i start mining? 74 | shouldStart int32 // Should i start mining after block sync? 75 | } 76 | 77 | type worker struct { 78 | config *params.ChainConfig 79 | engine consensus.Engine 80 | 81 | mu sync.Mutex 82 | 83 | // update loop 84 | mux *event.TypeMux 85 | txCh chan core.TxPreEvent 86 | txSub event.Subscription 87 | chainHeadCh chan core.ChainHeadEvent 88 | chainHeadSub event.Subscription 89 | chainSideCh chan core.ChainSideEvent 90 | chainSideSub event.Subscription 91 | wg sync.WaitGroup 92 | 93 | agents map[Agent]struct{} // worker have a map for Agents 94 | recv chan *Result 95 | 96 | eth Backend 97 | chain *core.BlockChain 98 | proc core.Validator 99 | chainDb ethdb.Database 100 | 101 | coinbase common.Address 102 | extra []byte 103 | 104 | currentMu sync.Mutex 105 | current *Work 106 | 107 | uncleMu sync.Mutex 108 | possibleUncles map[common.Hash]*types.Block 109 | 110 | unconfirmed *unconfirmedBlocks // 本地挖出的待确认的块 111 | 112 | mining int32 113 | atWork int32 114 | } 115 | 116 | // ChainConfig is the core config which determines the blockchain settings. 117 | // 118 | // ChainConfig is stored in the database on a per block basis. This means 119 | // that any network, identified by its genesis block, can have its own 120 | // set of configuration options. 121 | type ChainConfig struct { 122 | ChainID *big.Int `json:"chainId"` // chainId identifies the current chain and is used for replay protection 123 | 124 | HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead) 125 | 126 | DAOForkBlock *big.Int `json:"daoForkBlock,omitempty"` // TheDAO hard-fork switch block (nil = no fork) 127 | DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork 128 | 129 | // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) 130 | EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) 131 | EIP150Hash common.Hash `json:"eip150Hash,omitempty"` // EIP150 HF hash (needed for header only clients as only gas pricing changed) 132 | 133 | EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block 134 | EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block 135 | 136 | ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) 137 | ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated) 138 | PetersburgBlock *big.Int `json:"petersburgBlock,omitempty"` // Petersburg switch block (nil = same as Constantinople) 139 | IstanbulBlock *big.Int `json:"istanbulBlock,omitempty"` // Istanbul switch block (nil = no fork, 0 = already on istanbul) 140 | MuirGlacierBlock *big.Int `json:"muirGlacierBlock,omitempty"` // Eip-2384 (bomb delay) switch block (nil = no fork, 0 = already activated) 141 | BerlinBlock *big.Int `json:"berlinBlock,omitempty"` // Berlin switch block (nil = no fork, 0 = already on berlin) 142 | LondonBlock *big.Int `json:"londonBlock,omitempty"` // London switch block (nil = no fork, 0 = already on london) 143 | ArrowGlacierBlock *big.Int `json:"arrowGlacierBlock,omitempty"` // Eip-4345 (bomb delay) switch block (nil = no fork, 0 = already activated) 144 | GrayGlacierBlock *big.Int `json:"grayGlacierBlock,omitempty"` // Eip-5133 (bomb delay) switch block (nil = no fork, 0 = already activated) 145 | MergeNetsplitBlock *big.Int `json:"mergeNetsplitBlock,omitempty"` // Virtual fork after The Merge to use as a network splitter 146 | 147 | // Fork scheduling was switched from blocks to timestamps here 148 | 149 | ShanghaiTime *uint64 `json:"shanghaiTime,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai) 150 | CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun) 151 | PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) 152 | 153 | // TerminalTotalDifficulty is the amount of total difficulty reached by 154 | // the network that triggers the consensus upgrade. 155 | TerminalTotalDifficulty *big.Int `json:"terminalTotalDifficulty,omitempty"` 156 | 157 | // TerminalTotalDifficultyPassed is a flag specifying that the network already 158 | // passed the terminal total difficulty. Its purpose is to disable legacy sync 159 | // even without having seen the TTD locally (safer long term). 160 | TerminalTotalDifficultyPassed bool `json:"terminalTotalDifficultyPassed,omitempty"` 161 | 162 | // Various consensus engines 163 | Ethash *EthashConfig `json:"ethash,omitempty"` 164 | Clique *CliqueConfig `json:"clique,omitempty"` 165 | } 166 | ``` 167 | 168 | 169 | 170 | We need to analyze ChainConfig, because this configuration is very important, and we can trace the update of Ethereum through this configuration. 171 | 172 | 173 | 174 | ### ChainID 175 | 176 | The ChainID of Ethereum is an identifier used to differentiate between different Ethereum networks and prevent accidental interactions between them. In the Ethereum network, each block contains a ChainID field that specifies which network the block belongs to. 177 | 178 | In Ethereum, replay protection is a mechanism used to prevent transactions from being executed repeatedly across different networks. Replay protection is achieved by using network-specific transaction formats that include the ChainID field. When a transaction is sent to the network, nodes check whether the ChainID field in the transaction matches the ChainID of the network. If it doesn't match, the transaction is rejected. 179 | 180 | For example, when an Ethereum network forks, the new fork may use a different ChainID. If a user sends a transaction on the old network before the fork, that transaction may be replayed on the new fork by malicious nodes, resulting in unexpected loss of funds. By using ChainID to differentiate between networks and using network-specific transaction formats to protect against replay, this risk can be avoided. 181 | 182 | The exact number of ChainIDs may change over time due to network upgrades and forks. Here are some examples of ChainIDs for different Ethereum networks: 183 | 184 | - Mainnet: 1 185 | - Ropsten testnet: 3 186 | - Rinkeby testnet: 4 187 | - Kovan testnet: 42 188 | - Goerli testnet: 5 189 | - Ethereum Classic mainnet: 61 190 | 191 | 192 | 193 | ### HomesteadBlock 194 | 195 | The Homestead upgrade was planned as the first hard fork of the Ethereum network, implemented on March 14, 2016 at block 1,150,000. The Homestead upgrade mainly includes three important improvements to Ethereum. First, it removes the canary contract, removing the centralized part of the network. Second, it introduces new code in Solidity, Ethereum’s contract programming language. Finally, it introduces the Mist wallet, which allows users to hold/trade ETH and write/deploy smart contracts. 196 | 197 | The Homestead upgrade was one of the first Ethereum Improvement Proposals (EIPs) to be implemented. 198 | 199 | When the HomesteadBlock attribute is specified in ChainConfig, the Ethereum node will enable the Homestead upgrade after the specified block height. This helps ensure that all nodes on the Ethereum network implement the Homestead upgrade at the same block height and correctly handle the new opcodes and exception handling mechanisms. 200 | 201 | 202 | 203 | ### DAOForkBlock 204 | 205 | On the Ethereum blockchain, DAO (Decentralized Autonomous Organization) was a self-governing decentralized organization aimed at creating a decentralized investment fund through smart contracts. In 2016, DAO suffered a hack that resulted in over 3 million ether being stolen. To prevent further losses, the Ethereum community decided to perform a hard fork to roll back the transaction, which is known as the DAO fork. 206 | 207 | DAOForkBlock is an attribute in the Ethereum ChainConfig that defines the block height of the DAO fork on the Ethereum blockchain. Its purpose is to specify the time at which the DAO fork will take effect in the Ethereum software code. 208 | 209 | Specifically, if the DAO fork block height of an Ethereum node is lower than the DAOForkBlock attribute specified block height, then that node will follow the DAO smart contract. Otherwise, it will execute the new chain after the DAO fork. Therefore, the DAOForkBlock attribute is an important parameter in the Ethereum software that ensures the stability and security of the Ethereum blockchain. 210 | 211 | 212 | 213 | ### EIP150Block 214 | 215 | The purpose of the EIP150Block attribute is to ensure that Ethereum nodes can promptly apply the protocol changes specified by EIP-150 once the specified block height is reached, in order to improve the security and performance of the Ethereum network. 216 | 217 | Specifically, the changes introduced by EIP-150 include: 218 | 219 | 1. Adopting a more secure ECDSA signature algorithm (replacing the previous use of SECP256k1); 220 | 2. Modifying the miner reward mechanism, reducing block rewards and increasing the proportion of miner fees; 221 | 3. Modifying the state transition function to eliminate some potential security vulnerabilities. 222 | 223 | 224 | 225 | ### EIP155Block 226 | 227 | Before the implementation of the EIP-155 specification, Ethereum and Ethereum Classic (ETC) shared the same network ID and chain ID for a period of time, which caused confusion with transactions being replayed on both networks. The implementation of the EIP-155 specification resolved this issue, but it needed to take effect after a specific block height. Therefore, the EIP155Block property is used to specify the block height at which the EIP-155 specification was implemented on the Ethereum network. 228 | 229 | 230 | 231 | ### ByzantiumBlock 232 | 233 | After the Byzantium hard fork, the Ethereum network introduced some new features and improvements, including faster block confirmation times, better privacy and security, and better smart contract programming capabilities. These improvements require protocol upgrades to be implemented, so it is necessary to specify the ByzantiumBlock property to ensure that nodes on the network have already been upgraded. 234 | 235 | 236 | ### ShanghaiTime 237 | 238 | Ethereum nodes use the ShanghaiTime property to calculate the timestamps of blocks, ensuring that the timestamps in the blockchain are accurate and consistent with Shanghai time. This can be important for certain blockchain applications and smart contracts that need to determine the exact time something happened, such as in time-sensitive transactions that require proof of certain events. 239 | -------------------------------------------------------------------------------- /ethereum/ethereum-account-state.md: -------------------------------------------------------------------------------- 1 | # Ethereum Account and State 2 | 3 | There are two account models in the blockchain world: 4 | 5 | 1. UTXO (Unspent Transaction Output) model 6 | 2. account balance model 7 | 8 | 9 | 10 | UTXO does not record the account balance, but only records each transaction, and the account balance is obtained by calculating all historical transactions of the account (imagine if you know every transaction in your wife/husband’s bank account transaction, then you can figure out how much money she/he has on the card now). 11 | 12 | The account balance model is similar to the bank accounts we often use, and they all save the balance of our account. When someone transfers money to us, we add the value of the balance to the value of the transfer; when we transfer money to someone else, we subtract the value of the transfer from the number of the balance. 13 | 14 | From this point of view, the account balance model is relatively easy to understand. Ethereum uses the account balance model, and it is the state module that implements this model. It records the status of each account, and changes the status of the corresponding account whenever a transaction occurs. 15 | 16 | 17 | 18 | ### Why does Ethereum use a balance model instead of a UTXO model? 19 | 20 | 1. Programmable transactions: Ethereum is a **smart contract** platform that allows users to write programmatic smart contracts on the blockchain. This means that transactions in Ethereum may involve multiple inputs and outputs, rather than just one input and one output like in Bitcoin. This complex transaction structure makes the UTXO model difficult to implement, while the balance model is better suited to support these complex transactions. 21 | 2. State storage: **Smart contracts** in Ethereum can modify the contract state, which needs to be stored on the blockchain. If a UTXO model is used, every state change would require the creation of new unspent transaction outputs, which would result in huge transaction volumes and high blockchain storage costs. The balance model only needs to update the balance of the contract address, making it more efficient. 22 | 3. Computational cost: The execution of **smart contracts** in Ethereum requires computational resources. If a UTXO model is used, since each transaction output has its own value, the outputs must be split and recombined during contract execution, resulting in additional computational costs. The balance model only needs to maintain the balance of each address, making it simpler and more efficient. 23 | 24 | In summary, Ethereum uses the balance model to better support programmable transactions, reduce state storage costs, and computational costs. 25 | 26 | 27 | 28 | ### State Context 29 | 30 | #### state definition 31 | 32 | The information of an account is a **state**, and Ethereum is a collection of all **states**. For example, the initial **state** is: {A has 10 yuan, B has 0 yuan}, then A initiates a transaction and gives B 2 yuan, and the **state** becomes {A has 8 yuan, B has 2 yuan}, the intermediate process It's a **state** transition. 33 | 34 | The actual initial **state** of Ethereum is the genesis block, which is transferred to a new state every time a new block is generated. 35 | 36 | 37 | 38 | #### state indication 39 | 40 | Ethereum uses root to represent **state**. Ethereum uses **Trie** to organize the **state**. Trie can be understood as a combination of dictionary tree and Merkle tree. It has a tree root root. With this root, you can access all **state** data, that is, the information of each account, so Use root to represent a state. 41 | 42 | 43 | 44 | #### get state 45 | 46 | There is a field Root in the block header, so if you find the block header, you can get the state of the blockchain. 47 | 48 | 49 | 50 | #### Where does the state exist 51 | 52 | **State** does not exist in blocks. The root is stored in the block header, which is just an address, and the **state** data cannot be found from the block. 53 | 54 | **State is just temporary data that can be regenerated. The genesis block is the initial state. After executing all the transactions in the first block, a new state is obtained,** and the root of this state is stored in the Root of the first block header. If there are all blocks, all transactions can be executed, and then the state in the latest block can be generated. 55 | 56 | The state is stored in an external database. The underlying database of Ethereum is LevelDB, where the blocks are stored and the status is also stored in it. But the state is a Trie, which cannot be directly stored in LevelDB. 57 | 58 | Note: Although we can obtain the information of all accounts by traversing and executing all transactions in all blocks, the existence of state allows us to quickly obtain the balance of an account without performing such time-consuming operations every time. 59 | 60 | 61 | 62 | ### StateDB 63 | 64 | StateDB is the main object in the state module. It records the information of each account, including balance (number of ether), nonce and other information. 65 | 66 | The process of **transactions** being collected into **blocks** by **miners** is the process of **miners** performing **state** **transitions**. Even if there is no **transaction**, **miners** can directly migrate the world state to a new state, such as digging out empty blocks. 67 | 68 | Even in the early days of Ethereum, when Ethereum was running for three months, the local folder storage of Ethereum clients ballooned to a staggering 10 to 40 GB. As of block height 9001290, an Ethereum archive node that retains all state needs to occupy 216 GB of space. If these states are all recorded on the blockchain, then this will be a nightmare. 69 | 70 | This will make micro-devices such as Internet of Things devices, personal notebooks, and mobile phones unable to use the Ethereum client, which will lead to a decrease in the number of network nodes and affect user usage. Therefore, these states are not directly stored on the blockchain, but these states are maintained in the Merkle prefix tree, and only the corresponding tree Root value is recorded on the blockchain. Use a simple database to maintain the persistent content of the tree, and the database used to maintain the mapping is called StateDB. 71 | 72 | There are 2 types of state. 73 | 74 | - World state 75 | - Account state 76 | 77 | The following information is stored in the account status 78 | 79 | 1. **nonce**: This value is equal to the number of transactions issued by this account, or the number of contracts created by this account (when this account has an associated code). 80 | 2. **balance**: Indicates the account balance of this account. 81 | 3. **storageRoot**: Indicates the hash value of the root node of the MPT tree that saves the account storage content. 82 | 4. **codeHash**: Indicates the EVM code hash value of the account. When this address receives a message call, these codes will be executed; it is different from other fields and cannot be changed after creation. If codeHash is empty, it means that the account is a simple external account with only nonce and balance. 83 | 84 | ![state](..\pictures\state.webp) 85 | 86 | 87 | 88 | As shown in the figure above, all account states are maintained through the account address as the key, and the Merkle tree maintained is the world state. 89 | All accounts also have a tree representing the stored data of this account, which is independent and unique. 90 | 91 | The account status (such as account balance) can be found from the world state tree through the account address. If it is a contract address, you can also continue to use storageRoot to find the corresponding contract information from the account storage data tree (such as: in the auction contract. product information). 92 | 93 | 94 | 95 | ### How to init StateDB 96 | 97 | StateDB has many uses: 98 | 99 | 1. Maintain a mapping from account state to world state. 100 | 2. Support modification, rollback, commit status. 101 | 3. Supports persistent state to the database. 102 | 4. Is the medium through which states enter and exit the Merkle tree. 103 | 104 | 105 | 106 | At first, we should init a stateDB instance. 107 | 108 | First, we need to tell StateDB which state we want to use. Therefore, StateRoot needs to be provided as the root of the Merkle tree to build the tree. 109 | 110 | **The value of StateRoot is equivalent to the data version number**, according to the version number, it can be clearly known which version of the state to use. Of course, the data content is not in the tree and needs to be read in a database. Therefore, stateRoot and db need to be provided when building State DB to complete the build. 111 | 112 | 113 | 114 | ```go 115 | db: = state.NewDatabase(levelDB) 116 | statedb, err := state.New(block.Root(), db) 117 | 118 | //core/state/statedb.go:92 119 | func New(root common.Hash, db Database) (*StateDB, error) { 120 | tr, err := db.OpenTrie(root)//① 121 | if err != nil { 122 | return nil, err 123 | } 124 | return &StateDB{ 125 | db: db,//② 126 | trie: tr, 127 | stateObjects: make(map[common.Address]*stateObject), 128 | stateObjectsDirty: make(map[common.Address]struct{}), 129 | logs: make(map[common.Hash][]*types.Log), 130 | preimages: make(map[common.Hash][]byte), 131 | journal: newJournal(), 132 | }, nil 133 | } 134 | 135 | //core/state/statedb.go:59 136 | type StateDB struct { 137 | db Database 138 | trie Trie 139 | stateObjects map[common.Address]*stateObject 140 | stateObjectsDirty map[common.Address]struct{} 141 | dbErr error 142 | refund uint64 143 | 144 | thash, bhash common.Hash 145 | txIndex int 146 | logs map[common.Hash][]*types.Log 147 | logSize uint 148 | 149 | preimages map[common.Hash][]byte 150 | journal *journal // change log, can use this to revert change 151 | validRevisions []revision 152 | nextRevisionId int 153 | } 154 | 155 | // core/state/database.go:42 156 | type Database interface { 157 | OpenTrie(root common.Hash) (Trie, error) // Opens the top-level tree containing the world state for the specified state version (root). 158 | OpenStorageTrie(addrHash, root common.Hash) (Trie, error) // Open the account data storage tree of the specified state version (root) under the addrHash. addrHash is the account 159 | CopyTrie(Trie) Trie 160 | ContractCode(addrHash, codeHash common.Hash) ([]byte, error) // Get the contract of the addrHash, which must match the contract hash (codeHash) 161 | ContractCodeSize(addrHash, codeHash common.Hash) (int, error) 162 | 163 | // TrieDB retrieves the low level trie database used for data storage. 164 | TrieDB() *trie.Database 165 | } 166 | ``` 167 | 168 | Currently, there are two types of DBs that implement the Database interface, odrDatabase used by light nodes, and cachingDB with cache used by normal nodes. 169 | 170 | Because **light nodes do not store data**, they need to obtain data by querying other nodes, and odrDatabase is the encapsulation of this data reading method. 171 | 172 | An ordinary node has a built-in levelDB. In order to improve read and write performance, it is encapsulated once with cachingDB. 173 | 174 | 175 | 176 | ### How to use StateDB to change state 177 | 178 | All states are based on accounts. Any data must belong to a certain account state, and the world state is only a tree to establish a safe mapping. Accessible data can be divided into the following types: 179 | 180 | 1. Access account basic properties: Balance, Nonce, Root, CodeHash 181 | 2. Read contract account code 182 | 3. Read the content stored in the contract account 183 | 184 | For example, when we try to obtain the balance of an account, we need to specify the account address from the world state tree Trie, and then read the account state. 185 | 186 | 187 | 188 | ```go 189 | db: = state.NewDatabase(levelDB) 190 | block = blockchain.CurrentBlock() 191 | statedb, err := state.New(block.Root(), db) 192 | balance := statedb.GetBalance(addr1) 193 | 194 | //core/state/statedb.go:207 195 | func (self *StateDB) GetBalance(addr common.Address) *big.Int { 196 | stateObject := self.getStateObject(addr)//① 197 | if stateObject != nil { 198 | return stateObject.Balance()//③ 199 | } 200 | return common.Big0//② 201 | } 202 | 203 | // core/state/statedb.go:408 204 | func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) { 205 | if obj := self.stateObjects[addr]; obj != nil {//① 206 | if obj.deleted { 207 | return nil 208 | } 209 | return obj 210 | } 211 | 212 | enc, err := self.trie.TryGet(addr[:])//② 213 | if len(enc) == 0 { 214 | self.setError(err) 215 | return nil 216 | } 217 | var data Account 218 | if err := rlp.DecodeBytes(enc, &data); err != nil {//③ 219 | log.Error("Failed to decode state object", "addr", addr, "err", err) 220 | return nil 221 | } 222 | obj := newObject(self, addr, data)//④ 223 | self.setStateObject(obj) 224 | return obj 225 | } 226 | 227 | type stateObject struct { 228 | address common.Address/ 229 | addrHash common.Hash 230 | data Account 231 | db *StateDB 232 | 233 | //../ 存储树,第一次访问时初始化 234 | code Code // contract bytecode, which gets set when code is loaded 235 | //... 236 | } 237 | type Account struct { 238 | Nonce uint64 239 | Balance *big.Int 240 | Root common.Hash // merkle root of the storage trie 241 | CodeHash []byte 242 | } 243 | ``` 244 | 245 | 246 | 247 | ##### How to send ETH to another account? 248 | 249 | In Ethereum, A transfers 100 ETH to B, and actually completes two state modification operations in the current state: 250 | 251 | 1. A's account balance decreases by 100 ETH. 252 | 2. B's account balance increases by 100 ETH. 253 | 254 | 255 | 256 | ```go 257 | db: = state.NewDatabase(levelDB) 258 | block = blockchain.CurrentBlock() 259 | statedb, err := state.New(block.Root(), db) 260 | 261 | statedb.SubBalance(A,100 ETH) 262 | statedb.AddBalance(B,100 ETH) 263 | ``` 264 | 265 | 266 | 267 | ### How to use StateDB to read contract? 268 | 269 | The biggest difference between contract accounts and ordinary accounts is that they have their own storage tree 270 | 271 | ```go 272 | // core/state/state_object.go:152 273 | func (c *stateObject) getTrie(db Database) Trie { 274 | if c.trie == nil { 275 | var err error 276 | c.trie, err = db.OpenStorageTrie(c.addrHash, c.data.Root)//① 277 | if err != nil { 278 | c.trie, _ = db.OpenStorageTrie(c.addrHash, common.Hash{})//② 279 | c.setError(fmt.Errorf("can't create storage trie: %v", err)) 280 | } 281 | } 282 | return c.trie 283 | } 284 | ``` 285 | 286 | 287 | 288 | ### How to set changes StateDB into a real DB? 289 | 290 | StateDB can be regarded as an in-memory database. State data is first modified in the in-memory database, and all calculations about the state are completed in memory. When the block is persisted, the update storage from the memory to the database is completed. This update is an incremental update, and only the modification involves the modified part. 291 | 292 | ```go 293 | // core/state/statedb.go:680 294 | func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) { 295 | defer s.clearJournalAndRefund() 296 | 297 | for addr := range s.journal.dirties {//①⑧⑨⑩ 298 | s.stateObjectsDirty[addr] = struct{}{} 299 | } 300 | for addr, stateObject := range s.stateObjects {//② 301 | _, isDirty := s.stateObjectsDirty[addr] 302 | switch { 303 | case stateObject.suicided || (isDirty && deleteEmptyObjects && stateObject.empty()): 304 | //③ 305 | s.deleteStateObject(stateObject) 306 | case isDirty: 307 | if stateObject.code != nil && stateObject.dirtyCode {//④ 308 | s.db.TrieDB().InsertBlob(common.BytesToHash(stateObject.CodeHash()), stateObject.code) 309 | stateObject.dirtyCode = false 310 | } 311 | if err := stateObject.CommitTrie(s.db); err != nil {//⑤ 312 | return common.Hash{}, err 313 | } 314 | s.updateStateObject(stateObject)//⑥ 315 | } 316 | delete(s.stateObjectsDirty, addr) 317 | } 318 | //... 319 | root, err = s.trie.Commit(func(leaf []byte, parent common.Hash) error {//⑦ 320 | var account Account 321 | if err := rlp.DecodeBytes(leaf, &account); err != nil { 322 | return nil 323 | } 324 | if account.Root != emptyRoot { 325 | s.db.TrieDB().Reference(account.Root, parent) 326 | } 327 | code := common.BytesToHash(account.CodeHash) 328 | if code != emptyCode { 329 | s.db.TrieDB().Reference(code, parent) 330 | } 331 | return nil 332 | }) 333 | return root, err 334 | } 335 | ``` 336 | 337 | 338 | 339 | stateDB.Commit() will save the change to the db. 340 | 341 | ![commit](..\pictures\commit.png) 342 | 343 | ### How StateDB revert change? 344 | 345 | When a transaction is packaged into a block, when one of the transactions fails to execute, the transaction will not be included in the block, and the state needs to be rolled back to the state before the execution of the transaction. The code below is the logic code for the mining module to process transactions. 346 | 347 | ```go 348 | snap := w.current.state.Snapshot() 349 | receipt, _, err := core.ApplyTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig()) 350 | if err != nil { 351 | w.current.state.RevertToSnapshot(snap) 352 | return nil, err 353 | } 354 | ``` -------------------------------------------------------------------------------- /ethereum/ethereum-block-and-network.md: -------------------------------------------------------------------------------- 1 | # Ethereum Block and Network 2 | 3 | 4 | 5 | In all blockchain projects, the data structure composed of blocks is one of the core. The reason why it is called "blockchain" is precisely because these projects organize all blocks in a chain structure, and Ethereum is no exception. Of course, in addition to the chain structure, some other functions have been added to Ethereum, such as the maintenance of uncle blocks, main chain and side chain, etc. 6 | 7 | 8 | 9 | The code about the blockchain structure in Ethereum is located in three directories: 10 | 11 | 1. core (only contains go files in the directory) 12 | 2. core/rawdb 13 | 3. light 14 | 15 | 16 | 17 | The go file in the core directory contains almost all important functions and is the core code of the Ethereum blockchain. Among them, the BlockChain structure and method implemented in blockchain.go is the core implementation; the HeaderChain implemented in headerchain.go realizes the management of block headers. 18 | 19 | The core/rawdb directory implements methods for **reading and writing all block structures from the database**. From these codes you can see how the blockchain is organized in the code. 20 | 21 | The code in the light directory implements the organization and maintenance of the blockchain **in the light synchronization mode** (described later). 22 | 23 | 24 | 25 | ### What is Block and Chain 26 | 27 | From wiki, 28 | 29 | > Blockchain is a series of transaction records (also known as blocks) that are connected and protected by cryptography. Each block contains the encrypted hash of the previous block, the corresponding time stamp and transaction data (usually represented by the hash value calculated by the Merkle tree algorithm) [7], this design makes the content of the block difficult to tamper characteristics. The distributed ledger connected by the blockchain allows two parties to effectively record the transaction, and the transaction can be permanently verified. 30 | 31 | Almost all blockchain projects are essentially about recording and confirming **transactions**. And this recording and confirmation is carried out through blocks. That is to say, after the miners check the legality of some **transactions**, they are packaged in the form of **blocks**, thus generating a new block data. 32 | 33 | In each block, there will be a field to record the hash of its parent block. It is the hash of this parent block that forms the block into a one-way list structure similar to the data structure, also known as a "chain". 34 | 35 | This is what blockchain is about. 36 | The method of using the hash of the parent block to form a chain can prevent the block from being tampered with, because if a block is modified, its hash will change, resulting in a discrepancy with the hash recorded in the child block, thus making this Such modifications are not recognized. 37 | The benefits of forming a chain also include easier handling of branching (i.e. forking). Just imagine that if blocks are organized in the form of an array, if there is a branch, it will definitely not be as convenient as a linked list. 38 | 39 | 40 | 41 | The chain maybe looks like this, 42 | 43 | ![chains](../pictures/chains.png) 44 | 45 | 46 | 47 | 48 | 49 | Most blocks form a chain, and each block points to its own parent block until the **Genesis block**. But it is also easy to notice that there is not only one chain from the beginning to the end, but there are many long or short branch chains like "burrs". These branch chains are called **side chains**, and the main chain is the **main chain**, and this situation of branch chains is called a **fork**. 50 | 51 | Each block will have a **height**, which is a count of the block's position on the chain. For example, the height of the genesis block is 0 because it is the first block. The height of the second block is 1, and so on. If we carefully observe the block height in the figure, we will find that the height of the last block on the main chain is not the largest. This shows that in Ethereum, the block height is not used to judge whether it is the main chain or the side chain. We will discuss this issue in more detail later. 52 | 53 | Regardless of whether it is the main chain or the side chain, some blocks on the side chain are "included" back, that is to say, some blocks will not only point to the parent block, but may also point to the blocks of their own uncles. This is a more distinctive feature in Ethereum, called uncle block. 54 | 55 | There are also some blocks that are not on the chain, these blocks are called **future blocks**. Ethereum sometimes receives some blocks with timestamps that are much larger than the parent block, so these blocks are temporarily stored as "future blocks". Try adding it to the chain when the time comes. 56 | 57 | 58 | 59 | ### Blocks 60 | 61 | In core/types/block.go 62 | 63 | 64 | 65 | ```go 66 | // Block represents an entire block in the Ethereum blockchain. 67 | type Block struct { 68 | header *Header 69 | uncles []*Header 70 | transactions Transactions 71 | withdrawals Withdrawals 72 | 73 | // caches 74 | hash atomic.Value 75 | size atomic.Value 76 | 77 | // These fields are used by package eth to track 78 | // inter-peer block relay. 79 | ReceivedAt time.Time 80 | ReceivedFrom interface{} 81 | } 82 | 83 | // Header represents a block header in the Ethereum blockchain. 84 | type Header struct { 85 | ParentHash common.Hash `json:"parentHash" gencodec:"required"` 86 | UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` 87 | Coinbase common.Address `json:"miner"` //The address that accepts block rewards. Miners fill in their own addresses in this field when producing blocks. 88 | Root common.Hash `json:"stateRoot" gencodec:"required"` // Hash of state, after all transactions done 89 | TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` // hash of Block.transactions 90 | ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` // Receipt Hash 91 | Bloom Bloom `json:"logsBloom" gencodec:"required"` // bloom filter to find the log 92 | Difficulty *big.Int `json:"difficulty" gencodec:"required"` 93 | Number *big.Int `json:"number" gencodec:"required"` 94 | GasLimit uint64 `json:"gasLimit" gencodec:"required"` // Upper for gas 95 | GasUsed uint64 `json:"gasUsed" gencodec:"required"` // used gas 96 | Time uint64 `json:"timestamp" gencodec:"required"` // Timestamp 97 | Extra []byte `json:"extraData" gencodec:"required"` // extra Data, anything could be possible 98 | MixDigest common.Hash `json:"mixHash"` // hashimoto 99 | Nonce BlockNonce `json:"nonce"` //For PoW Miner 100 | 101 | // BaseFee was added by EIP-1559 and is ignored in legacy headers. 102 | BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` 103 | 104 | // WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers. 105 | WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` 106 | 107 | /* 108 | TODO (MariusVanDerWijden) Add this field once needed 109 | // Random was added during the merge and contains the BeaconState randomness 110 | Random common.Hash `json:"random" rlp:"optional"` 111 | */ 112 | } 113 | ``` 114 | 115 | More important fields about Block, 116 | 117 | - Total Difficulty(Td) 118 | 119 | - ```go 120 | // TotalDifficultyAt calculates the total difficulty of the chain 121 | // at the given block height. 122 | func (c *Chain) TotalDifficultyAt(height int) *big.Int { 123 | sum := new(big.Int) 124 | if height >= c.Len() { 125 | return sum 126 | } 127 | for _, block := range c.blocks[:height+1] { 128 | sum.Add(sum, block.Difficulty()) 129 | } 130 | return sum 131 | } 132 | ``` 133 | 134 | - receipts 135 | 136 | - txlookupentries 137 | 138 | - It is used to query which block the transaction belongs to through the transaction hash. 139 | 140 | - state 141 | 142 | - all accounts info. 143 | 144 | 145 | 146 | ### Chain and sidechains 147 | 148 | The **chain** is the recognized chain, and subsequent newly generated blocks use the last block of the **chain** as the parent block. 149 | 150 | **Sidechains** are unacknowledged chains that may continue to grow, or stop there. If it continues to grow, its Td value may exceed the **chain** and become the **chain**. At this time, the original **chain** becomes a **sidechain** instead. 151 | 152 | Ideally, all blocks are added one by one on the **chain**. The reality is that the blockchain project is a distributed project, and the nodes did not trust each other before. Suppose nodes A and B generate a **block** with the same height, and they respectively tell other nodes about this news. Then some nodes add A's block to the **chain**, and some nodes add B's block to the **chain**. This situation creates a **fork**. 153 | 154 | If there is only one **chain** and nodes do not recognize other branches, then this **fork** will continue forever. This is obviously not acceptable. 155 | 156 | Therefore, in Ethereum, the **chain** and **sidechains** exist in the database at the same time. Every time a new **block** is added, it is re-judging whether the branch where the newly added block is located has become the **chain**. If it becomes the **chain**, it needs to be adjusted, and the branch where the newly added block is located becomes the **chain**, and the original **chain** is canceled at the same time. 157 | 158 | 159 | 160 | This is the code how Blockchain decide to reorg. 161 | 162 | ```go 163 | // writeBlockWithState writes block, metadata and corresponding state data to the 164 | // database. 165 | func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) error { 166 | // Calculate the total difficulty of the block 167 | ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1) 168 | if ptd == nil { 169 | return consensus.ErrUnknownAncestor 170 | } 171 | // Make sure no inconsistent state is leaked during insertion 172 | externTd := new(big.Int).Add(block.Difficulty(), ptd) 173 | 174 | // Irrelevant of the canonical status, write the block itself to the database. 175 | // 176 | // Note all the components of block(td, hash->number map, header, body, receipts) 177 | // should be written atomically. BlockBatch is used for containing all components. 178 | blockBatch := bc.db.NewBatch() 179 | rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) 180 | rawdb.WriteBlock(blockBatch, block) 181 | rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) 182 | rawdb.WritePreimages(blockBatch, state.Preimages()) 183 | if err := blockBatch.Write(); err != nil { 184 | log.Crit("Failed to write block into disk", "err", err) 185 | } 186 | // Commit all cached state changes into underlying memory database. 187 | root, err := state.Commit(bc.chainConfig.IsEIP158(block.Number())) 188 | if err != nil { 189 | return err 190 | } 191 | // If we're running an archive node, always flush 192 | if bc.cacheConfig.TrieDirtyDisabled { 193 | return bc.triedb.Commit(root, false) 194 | } 195 | // Full but not archive node, do proper garbage collection 196 | bc.triedb.Reference(root, common.Hash{}) // metadata reference to keep trie alive 197 | bc.triegc.Push(root, -int64(block.NumberU64())) 198 | 199 | current := block.NumberU64() 200 | // Flush limits are not considered for the first TriesInMemory blocks. 201 | if current <= TriesInMemory { 202 | return nil 203 | } 204 | // If we exceeded our memory allowance, flush matured singleton nodes to disk 205 | var ( 206 | nodes, imgs = bc.triedb.Size() 207 | limit = common.StorageSize(bc.cacheConfig.TrieDirtyLimit) * 1024 * 1024 208 | ) 209 | if nodes > limit || imgs > 4*1024*1024 { 210 | bc.triedb.Cap(limit - ethdb.IdealBatchSize) 211 | } 212 | // Find the next state trie we need to commit 213 | chosen := current - TriesInMemory 214 | flushInterval := time.Duration(atomic.LoadInt64(&bc.flushInterval)) 215 | // If we exceeded time allowance, flush an entire trie to disk 216 | if bc.gcproc > flushInterval { 217 | // If the header is missing (canonical chain behind), we're reorging a low 218 | // diff sidechain. Suspend committing until this operation is completed. 219 | header := bc.GetHeaderByNumber(chosen) 220 | if header == nil { 221 | log.Warn("Reorg in progress, trie commit postponed", "number", chosen) 222 | } else { 223 | // If we're exceeding limits but haven't reached a large enough memory gap, 224 | // warn the user that the system is becoming unstable. 225 | if chosen < bc.lastWrite+TriesInMemory && bc.gcproc >= 2*flushInterval { 226 | log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", flushInterval, "optimum", float64(chosen-bc.lastWrite)/TriesInMemory) 227 | } 228 | // Flush an entire trie and restart the counters 229 | bc.triedb.Commit(header.Root, true) 230 | bc.lastWrite = chosen 231 | bc.gcproc = 0 232 | } 233 | } 234 | // Garbage collect anything below our required write retention 235 | for !bc.triegc.Empty() { 236 | root, number := bc.triegc.Pop() 237 | if uint64(-number) > chosen { 238 | bc.triegc.Push(root, number) 239 | break 240 | } 241 | bc.triedb.Dereference(root) 242 | } 243 | return nil 244 | } 245 | ``` 246 | 247 | 248 | 249 | This is the Blockchain how to reorg. 250 | 251 | ```go 252 | // reorg takes two blocks, an old chain and a new chain and will reconstruct the 253 | // blocks and inserts them to be part of the new canonical chain and accumulates 254 | // potential missing transactions and post an event about them. 255 | // Note the new head block won't be processed here, callers need to handle it 256 | // externally. 257 | func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { 258 | var ( 259 | newChain types.Blocks 260 | oldChain types.Blocks 261 | commonBlock *types.Block 262 | 263 | deletedTxs []common.Hash 264 | addedTxs []common.Hash 265 | ) 266 | // Reduce the longer chain to the same number as the shorter one 267 | // Find the common ancestor commonBlock of the two branches of oldBlock and newBlock, Record all blocks on the path to the common ancestor in newChain and oldChain respectively. At the same time, put all transactions on the branch of oldBlock into deletedTxs. 268 | if oldBlock.NumberU64() > newBlock.NumberU64() { 269 | ... 270 | } 271 | } 272 | ``` 273 | 274 | 275 | 276 | The method of writing a block to the main chain is actually very simple, that is, to create a record from the block height to the block hash in the database. When we only use the block height to get a block, what we get is the block on the main chain; at the same time, the main chain will have a mark that records the hash of the latest block on the main chain. 277 | 278 | 279 | 280 | ### pruned block 281 | 282 | In October 2017, the data of Ethereum had reached more than 300G, and it would soon exceed 1T. Such a large amount of data is unacceptable for an ordinary user. 283 | 284 | The Ethereum team solved this problem by pruning block data. To be precise, what is pruned is actually state data, because the final reason for the rapid growth of Ethereum data is not the increase in the number of blocks, but the growth of state data. So why does the amount of state data grow so fast? This starts with how the state is implemented. 285 | 286 | 287 | 288 | Is it necessary for an Ethereum node to store all historical data of the state? In most cases it is not needed. For those data that are not needed, we can not store them. In case we need to use it one day, we can spend some time to recalculate the data because the complete block information is saved. 289 | 290 | The method provided by Ethereum is to prune the nodes of the trie tree. In the implementation of trie, "reference counting" will be performed on the nodes existing in memory, that is, each node has a number that records the number of times it is referenced. When the number of references becomes 0, the node memory will be released. will not be written to the database. 291 | 292 | 293 | 294 | ### 3 Synchronization Modes 295 | 296 | full、fast、light. 297 | 298 | ##### full mode 299 | 300 | As the name suggests, "full mode" synchronizes all block data. In full mode, the synchronization module calls BlockChain.InsertChain to insert block data obtained from other nodes into the database. In BlockChain.InsertChain, the state and receipts data of each block will be calculated and verified one by one. If everything is normal, the synchronized block data and the state and receipts data calculated by itself will be written into the database together. 301 | 302 | Note that there are two processing methods in full mode, one of which saves all historical data, and this node is called "archive node". The other prunes the state. To become an "archive node", set the NoPruning field in the configuration file to true. 303 | 304 | ##### fast mode 305 | 306 | The so-called "quick mode" is relative to the "full mode". In full mode, the state and receipts are calculated on the current machine based on the transactions in the block data. In fast mode, state and receipts are no longer calculated locally, but are directly synchronized from other nodes just like block data. Therefore, in the fast mode, the synchronous mode calls BlockChain.InsertReceiptChain to write the synchronized blocks and receipts directly into the blockchain database; and the state is also directly written into the library through stateDb. 307 | 308 | There is a currentFastBlock field in BlockChain, which represents the latest block on the main chain in fast mode. 309 | 310 | It can be seen that the fast mode replaces the local calculation of the state and receipts in the full mode by using the network direct synchronization method, and replaces the local computing resources with the network bandwidth. 311 | 312 | ##### light mode 313 | 314 | Light mode, also called light mode, is a mode that only synchronizes block headers. In the light mode, the blockchain organization does not use the blockchain module, but the light module. This module is located in the "light" directory under the Ethereum project. The biggest difference from the blockchain module is that the light module only calls the related methods of HeaderChain to process the block header, but not other data. Only when other data other than the header of a certain block is needed, the required data is obtained. 315 | 316 | When calling loadLastState, if the state of currentBlock does not exist, then call repair to obtain and search up the currentBlock until a state exists. 317 | 318 | 319 | 320 | 321 | 322 | ### Questions 323 | 324 | 325 | 326 | - What is the average block interval time of Ethereum? 327 | - The average block interval time of Ethereum is around 13-15 seconds 328 | - What is the average block size of Ethereum? 329 | - The average block size of Ethereum varies depending on the number of transactions being processed, but it typically ranges between 20-30 kilobytes. 330 | - What are nodes in Ethereum? How can one connect to Ethereum nodes? 331 | - Nodes in Ethereum refer to any computer or device that is connected to the Ethereum network and participates in validating transactions and maintaining the blockchain. One can connect to Ethereum nodes using a client program such as Geth or Parity, which allows communication with the network through the use of JSON-RPC APIs. 332 | - What are the methods for interacting with the Ethereum network? 333 | - There are several methods for interacting with the Ethereum network, including: 334 | - Using a client program such as Geth or Parity 335 | - Using a web3.js library to communicate with the network through a web browser 336 | - Utilizing a third-party service or API provider 337 | - Deploying and interacting with smart contracts on the Ethereum Virtual Machine (EVM) 338 | - Name some Types of Ethereum Networks? 339 | - Some types of Ethereum networks include the mainnet, testnets such as Ropsten and Rinkeby, and private networks used for development and testing purposes. 340 | - What is an Ethereum Client? 341 | - An Ethereum client is a software program that is used to connect to the Ethereum network and participate in the validation of transactions and maintenance of the blockchain. Examples of Ethereum clients include Geth, Parity, and Besu. 342 | - How does a blockchain recognize a Block? 343 | - A blockchain recognizes a block through a combination of its hash value, which is calculated based on the transactions contained within the block, and the hash value of the previous block in the chain. When a new block is added to the blockchain, it must be validated by a network of nodes to ensure that its hash value matches the previous block and that its transactions are valid. 344 | - In a Blockchain database, what various kinds of records can you find? 345 | - In a blockchain database, you can find various kinds of records, including transactions, blocks, addresses, and smart contracts. Transactions record the transfer of cryptocurrency or other assets between parties, blocks group transactions together and form the basis of the blockchain, addresses are unique identifiers used to send and receive assets, and smart contracts are self-executing code that can be deployed and executed on the blockchain. 346 | - Is it possible to make changes to the data after it has been written in a block? 347 | - Once data has been written to a block on the blockchain, it is extremely difficult, if not impossible, to change it. This is because the blockchain uses a cryptographic hash function to link each block to the previous one, creating an immutable chain of blocks. Any attempt to modify the data in a block would change its hash value, which would in turn invalidate all the subsequent blocks in the chain. Therefore, the blockchain is considered to be a secure and tamper-resistant way to store data. 348 | - Why use Ethereum private chains when the Ethereum main chain is already powerful? 349 | - While the Ethereum main chain is powerful and widely used, there are situations where a private Ethereum blockchain may be more appropriate. Private chains offer greater control over the network, allowing organizations to customize network parameters and restrict access to specific participants. This can be useful for companies that require a high degree of privacy, security, and control over their data and applications. Private chains can also offer faster transaction times and lower transaction fees compared to the public Ethereum network. 350 | - How can I view detailed information about a transaction or block? 351 | - To view detailed information about a transaction or block on the Ethereum main chain, you can use a blockchain explorer such as Etherscan. Simply enter the transaction hash or block number into the search bar and you will be able to see detailed information about the transaction or block, including the sender and recipient addresses, transaction fee, gas used, and more. 352 | - How can I view detailed information about a transaction or block on a private Ethereum chain? 353 | - To view detailed information about a transaction or block on a private Ethereum chain, you will need to access the blockchain's node or use a blockchain explorer specifically designed for that private chain. Depending on the specific implementation of the private chain, you may need to obtain special permissions or access credentials to view this information. -------------------------------------------------------------------------------- /ethereum/erc721-token.md: -------------------------------------------------------------------------------- 1 | # ERC-721 2 | 3 | ```solidity 4 | pragma solidity ^0.8.0; 5 | 6 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 7 | import "@openzeppelin/contracts/utils/Counters.sol"; 8 | 9 | contract MyNFT is ERC721 { 10 | using Counters for Counters.Counter; 11 | Counters.Counter private _tokenIds; 12 | 13 | constructor() ERC721("MyNFT", "MNFT") {} 14 | 15 | function createToken(address owner, string memory tokenURI) public returns (uint256) { 16 | _tokenIds.increment(); 17 | 18 | uint256 newTokenId = _tokenIds.current(); 19 | _mint(owner, newTokenId); 20 | _setTokenURI(newTokenId, tokenURI); 21 | 22 | return newTokenId; 23 | } 24 | } 25 | 26 | MyNFT myNFT = new MyNFT(); 27 | 28 | for (uint i=0; i<20; i++) { 29 | string memory tokenURI = string(abi.encodePacked("https://example.com/nft/", i)); 30 | myNFT.createToken(msg.sender, tokenURI); 31 | } 32 | ``` 33 | 34 | 35 | 36 | ### BoredApeYachtClub 37 | 38 | Let us see the smart contract of BoredApeYachtClub (BAYC). 39 | 40 | https://etherscan.io/token/0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d#code 41 | 42 | ```solidity 43 | ... 44 | 45 | /** 46 | * @title ERC721 Non-Fungible Token Standard basic implementation 47 | * @dev see https://eips.ethereum.org/EIPS/eip-721 48 | */ 49 | contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Enumerable { 50 | using SafeMath for uint256; 51 | using Address for address; 52 | using EnumerableSet for EnumerableSet.UintSet; 53 | using EnumerableMap for EnumerableMap.UintToAddressMap; 54 | using Strings for uint256; 55 | 56 | // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` 57 | // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` 58 | bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; 59 | 60 | // Mapping from holder address to their (enumerable) set of owned tokens 61 | mapping (address => EnumerableSet.UintSet) private _holderTokens; 62 | 63 | // Enumerable mapping from token ids to their owners 64 | EnumerableMap.UintToAddressMap private _tokenOwners; 65 | 66 | // Mapping from token ID to approved address 67 | mapping (uint256 => address) private _tokenApprovals; 68 | 69 | // Mapping from owner to operator approvals 70 | mapping (address => mapping (address => bool)) private _operatorApprovals; 71 | 72 | // Token name 73 | string private _name; 74 | 75 | // Token symbol 76 | string private _symbol; 77 | 78 | // Optional mapping for token URIs 79 | mapping (uint256 => string) private _tokenURIs; 80 | 81 | // Base URI 82 | string private _baseURI; 83 | 84 | /* 85 | * bytes4(keccak256('balanceOf(address)')) == 0x70a08231 86 | * bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e 87 | * bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3 88 | * bytes4(keccak256('getApproved(uint256)')) == 0x081812fc 89 | * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 90 | * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5 91 | * bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd 92 | * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e 93 | * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde 94 | * 95 | * => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^ 96 | * 0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd 97 | */ 98 | bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; 99 | 100 | /* 101 | * bytes4(keccak256('name()')) == 0x06fdde03 102 | * bytes4(keccak256('symbol()')) == 0x95d89b41 103 | * bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd 104 | * 105 | * => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f 106 | */ 107 | bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f; 108 | 109 | /* 110 | * bytes4(keccak256('totalSupply()')) == 0x18160ddd 111 | * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59 112 | * bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7 113 | * 114 | * => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63 115 | */ 116 | bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63; 117 | 118 | /** 119 | * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. 120 | */ 121 | constructor (string memory name_, string memory symbol_) public { 122 | _name = name_; 123 | _symbol = symbol_; 124 | 125 | // register the supported interfaces to conform to ERC721 via ERC165 126 | _registerInterface(_INTERFACE_ID_ERC721); 127 | _registerInterface(_INTERFACE_ID_ERC721_METADATA); 128 | _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE); 129 | } 130 | 131 | /** 132 | * @dev See {IERC721-balanceOf}. 133 | */ 134 | function balanceOf(address owner) public view virtual override returns (uint256) { 135 | require(owner != address(0), "ERC721: balance query for the zero address"); 136 | return _holderTokens[owner].length(); 137 | } 138 | 139 | /** 140 | * @dev See {IERC721-ownerOf}. 141 | */ 142 | function ownerOf(uint256 tokenId) public view virtual override returns (address) { 143 | return _tokenOwners.get(tokenId, "ERC721: owner query for nonexistent token"); 144 | } 145 | 146 | /** 147 | * @dev See {IERC721Metadata-name}. 148 | */ 149 | function name() public view virtual override returns (string memory) { 150 | return _name; 151 | } 152 | 153 | /** 154 | * @dev See {IERC721Metadata-symbol}. 155 | */ 156 | function symbol() public view virtual override returns (string memory) { 157 | return _symbol; 158 | } 159 | 160 | /** 161 | * @dev See {IERC721Metadata-tokenURI}. 162 | */ 163 | function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { 164 | require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token"); 165 | 166 | string memory _tokenURI = _tokenURIs[tokenId]; 167 | string memory base = baseURI(); 168 | 169 | // If there is no base URI, return the token URI. 170 | if (bytes(base).length == 0) { 171 | return _tokenURI; 172 | } 173 | // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). 174 | if (bytes(_tokenURI).length > 0) { 175 | return string(abi.encodePacked(base, _tokenURI)); 176 | } 177 | // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI. 178 | return string(abi.encodePacked(base, tokenId.toString())); 179 | } 180 | 181 | /** 182 | * @dev Returns the base URI set via {_setBaseURI}. This will be 183 | * automatically added as a prefix in {tokenURI} to each token's URI, or 184 | * to the token ID if no specific URI is set for that token ID. 185 | */ 186 | function baseURI() public view virtual returns (string memory) { 187 | return _baseURI; 188 | } 189 | 190 | /** 191 | * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. 192 | */ 193 | function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { 194 | return _holderTokens[owner].at(index); 195 | } 196 | 197 | /** 198 | * @dev See {IERC721Enumerable-totalSupply}. 199 | */ 200 | function totalSupply() public view virtual override returns (uint256) { 201 | // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds 202 | return _tokenOwners.length(); 203 | } 204 | 205 | /** 206 | * @dev See {IERC721Enumerable-tokenByIndex}. 207 | */ 208 | function tokenByIndex(uint256 index) public view virtual override returns (uint256) { 209 | (uint256 tokenId, ) = _tokenOwners.at(index); 210 | return tokenId; 211 | } 212 | 213 | /** 214 | * @dev See {IERC721-approve}. 215 | */ 216 | function approve(address to, uint256 tokenId) public virtual override { 217 | address owner = ERC721.ownerOf(tokenId); 218 | require(to != owner, "ERC721: approval to current owner"); 219 | 220 | require(_msgSender() == owner || ERC721.isApprovedForAll(owner, _msgSender()), 221 | "ERC721: approve caller is not owner nor approved for all" 222 | ); 223 | 224 | _approve(to, tokenId); 225 | } 226 | 227 | /** 228 | * @dev See {IERC721-getApproved}. 229 | */ 230 | function getApproved(uint256 tokenId) public view virtual override returns (address) { 231 | require(_exists(tokenId), "ERC721: approved query for nonexistent token"); 232 | 233 | return _tokenApprovals[tokenId]; 234 | } 235 | 236 | /** 237 | * @dev See {IERC721-setApprovalForAll}. 238 | */ 239 | function setApprovalForAll(address operator, bool approved) public virtual override { 240 | require(operator != _msgSender(), "ERC721: approve to caller"); 241 | 242 | _operatorApprovals[_msgSender()][operator] = approved; 243 | emit ApprovalForAll(_msgSender(), operator, approved); 244 | } 245 | 246 | /** 247 | * @dev See {IERC721-isApprovedForAll}. 248 | */ 249 | function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { 250 | return _operatorApprovals[owner][operator]; 251 | } 252 | 253 | /** 254 | * @dev See {IERC721-transferFrom}. 255 | */ 256 | function transferFrom(address from, address to, uint256 tokenId) public virtual override { 257 | //solhint-disable-next-line max-line-length 258 | require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); 259 | 260 | _transfer(from, to, tokenId); 261 | } 262 | 263 | /** 264 | * @dev See {IERC721-safeTransferFrom}. 265 | */ 266 | function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { 267 | safeTransferFrom(from, to, tokenId, ""); 268 | } 269 | 270 | /** 271 | * @dev See {IERC721-safeTransferFrom}. 272 | */ 273 | function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override { 274 | require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved"); 275 | _safeTransfer(from, to, tokenId, _data); 276 | } 277 | 278 | /** 279 | * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients 280 | * are aware of the ERC721 protocol to prevent tokens from being forever locked. 281 | * 282 | * `_data` is additional data, it has no specified format and it is sent in call to `to`. 283 | * 284 | * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. 285 | * implement alternative mechanisms to perform token transfer, such as signature-based. 286 | * 287 | * Requirements: 288 | * 289 | * - `from` cannot be the zero address. 290 | * - `to` cannot be the zero address. 291 | * - `tokenId` token must exist and be owned by `from`. 292 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 293 | * 294 | * Emits a {Transfer} event. 295 | */ 296 | function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual { 297 | _transfer(from, to, tokenId); 298 | require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); 299 | } 300 | 301 | /** 302 | * @dev Returns whether `tokenId` exists. 303 | * 304 | * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. 305 | * 306 | * Tokens start existing when they are minted (`_mint`), 307 | * and stop existing when they are burned (`_burn`). 308 | */ 309 | function _exists(uint256 tokenId) internal view virtual returns (bool) { 310 | return _tokenOwners.contains(tokenId); 311 | } 312 | 313 | /** 314 | * @dev Returns whether `spender` is allowed to manage `tokenId`. 315 | * 316 | * Requirements: 317 | * 318 | * - `tokenId` must exist. 319 | */ 320 | function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { 321 | require(_exists(tokenId), "ERC721: operator query for nonexistent token"); 322 | address owner = ERC721.ownerOf(tokenId); 323 | return (spender == owner || getApproved(tokenId) == spender || ERC721.isApprovedForAll(owner, spender)); 324 | } 325 | 326 | /** 327 | * @dev Safely mints `tokenId` and transfers it to `to`. 328 | * 329 | * Requirements: 330 | d* 331 | * - `tokenId` must not exist. 332 | * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. 333 | * 334 | * Emits a {Transfer} event. 335 | */ 336 | function _safeMint(address to, uint256 tokenId) internal virtual { 337 | _safeMint(to, tokenId, ""); 338 | } 339 | 340 | /** 341 | * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is 342 | * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. 343 | */ 344 | function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual { 345 | _mint(to, tokenId); 346 | require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); 347 | } 348 | 349 | /** 350 | * @dev Mints `tokenId` and transfers it to `to`. 351 | * 352 | * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible 353 | * 354 | * Requirements: 355 | * 356 | * - `tokenId` must not exist. 357 | * - `to` cannot be the zero address. 358 | * 359 | * Emits a {Transfer} event. 360 | */ 361 | function _mint(address to, uint256 tokenId) internal virtual { 362 | require(to != address(0), "ERC721: mint to the zero address"); 363 | require(!_exists(tokenId), "ERC721: token already minted"); 364 | 365 | _beforeTokenTransfer(address(0), to, tokenId); 366 | 367 | _holderTokens[to].add(tokenId); 368 | 369 | _tokenOwners.set(tokenId, to); 370 | 371 | emit Transfer(address(0), to, tokenId); 372 | } 373 | 374 | /** 375 | * @dev Destroys `tokenId`. 376 | * The approval is cleared when the token is burned. 377 | * 378 | * Requirements: 379 | * 380 | * - `tokenId` must exist. 381 | * 382 | * Emits a {Transfer} event. 383 | */ 384 | function _burn(uint256 tokenId) internal virtual { 385 | address owner = ERC721.ownerOf(tokenId); // internal owner 386 | 387 | _beforeTokenTransfer(owner, address(0), tokenId); 388 | 389 | // Clear approvals 390 | _approve(address(0), tokenId); 391 | 392 | // Clear metadata (if any) 393 | if (bytes(_tokenURIs[tokenId]).length != 0) { 394 | delete _tokenURIs[tokenId]; 395 | } 396 | 397 | _holderTokens[owner].remove(tokenId); 398 | 399 | _tokenOwners.remove(tokenId); 400 | 401 | emit Transfer(owner, address(0), tokenId); 402 | } 403 | 404 | /** 405 | * @dev Transfers `tokenId` from `from` to `to`. 406 | * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. 407 | * 408 | * Requirements: 409 | * 410 | * - `to` cannot be the zero address. 411 | * - `tokenId` token must be owned by `from`. 412 | * 413 | * Emits a {Transfer} event. 414 | */ 415 | function _transfer(address from, address to, uint256 tokenId) internal virtual { 416 | require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own"); // internal owner 417 | require(to != address(0), "ERC721: transfer to the zero address"); 418 | 419 | _beforeTokenTransfer(from, to, tokenId); 420 | 421 | // Clear approvals from the previous owner 422 | _approve(address(0), tokenId); 423 | 424 | _holderTokens[from].remove(tokenId); 425 | _holderTokens[to].add(tokenId); 426 | 427 | _tokenOwners.set(tokenId, to); 428 | 429 | emit Transfer(from, to, tokenId); 430 | } 431 | 432 | /** 433 | * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. 434 | * 435 | * Requirements: 436 | * 437 | * - `tokenId` must exist. 438 | */ 439 | function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { 440 | require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token"); 441 | _tokenURIs[tokenId] = _tokenURI; 442 | } 443 | 444 | /** 445 | * @dev Internal function to set the base URI for all token IDs. It is 446 | * automatically added as a prefix to the value returned in {tokenURI}, 447 | * or to the token ID if {tokenURI} is empty. 448 | */ 449 | function _setBaseURI(string memory baseURI_) internal virtual { 450 | _baseURI = baseURI_; 451 | } 452 | 453 | /** 454 | * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. 455 | * The call is not executed if the target address is not a contract. 456 | * 457 | * @param from address representing the previous owner of the given token ID 458 | * @param to target address that will receive the tokens 459 | * @param tokenId uint256 ID of the token to be transferred 460 | * @param _data bytes optional data to send along with the call 461 | * @return bool whether the call correctly returned the expected magic value 462 | */ 463 | function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) 464 | private returns (bool) 465 | { 466 | if (!to.isContract()) { 467 | return true; 468 | } 469 | bytes memory returndata = to.functionCall(abi.encodeWithSelector( 470 | IERC721Receiver(to).onERC721Received.selector, 471 | _msgSender(), 472 | from, 473 | tokenId, 474 | _data 475 | ), "ERC721: transfer to non ERC721Receiver implementer"); 476 | bytes4 retval = abi.decode(returndata, (bytes4)); 477 | return (retval == _ERC721_RECEIVED); 478 | } 479 | 480 | /** 481 | * @dev Approve `to` to operate on `tokenId` 482 | * 483 | * Emits an {Approval} event. 484 | */ 485 | function _approve(address to, uint256 tokenId) internal virtual { 486 | _tokenApprovals[tokenId] = to; 487 | emit Approval(ERC721.ownerOf(tokenId), to, tokenId); // internal owner 488 | } 489 | 490 | /** 491 | * @dev Hook that is called before any token transfer. This includes minting 492 | * and burning. 493 | * 494 | * Calling conditions: 495 | * 496 | * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be 497 | * transferred to `to`. 498 | * - When `from` is zero, `tokenId` will be minted for `to`. 499 | * - When `to` is zero, ``from``'s `tokenId` will be burned. 500 | * - `from` cannot be the zero address. 501 | * - `to` cannot be the zero address. 502 | * 503 | * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. 504 | */ 505 | function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual { } 506 | } 507 | 508 | // File: @openzeppelin/contracts/access/Ownable.sol 509 | 510 | 511 | 512 | ... 513 | 514 | pragma solidity ^0.7.0; 515 | 516 | 517 | 518 | /** 519 | * @title BoredApeYachtClub contract 520 | * @dev Extends ERC721 Non-Fungible Token Standard basic implementation 521 | */ 522 | contract BoredApeYachtClub is ERC721, Ownable { 523 | using SafeMath for uint256; 524 | 525 | string public BAYC_PROVENANCE = ""; 526 | 527 | uint256 public startingIndexBlock; 528 | 529 | uint256 public startingIndex; 530 | 531 | // price to build an ape 532 | uint256 public constant apePrice = 80000000000000000; //0.08 ETH 533 | 534 | uint public constant maxApePurchase = 20; 535 | 536 | uint256 public MAX_APES; // This is very important. This number ensures that there is an upper limit to the number of apes. And this number cannot be updated. 537 | 538 | bool public saleIsActive = false; 539 | 540 | uint256 public REVEAL_TIMESTAMP; 541 | 542 | constructor(string memory name, string memory symbol, uint256 maxNftSupply, uint256 saleStart) ERC721(name, symbol) { 543 | MAX_APES = maxNftSupply; 544 | REVEAL_TIMESTAMP = saleStart + (86400 * 9); 545 | } 546 | 547 | // Send balance of the contract account to owner acc 548 | function withdraw() public onlyOwner { 549 | uint balance = address(this).balance; 550 | msg.sender.transfer(balance); 551 | } 552 | 553 | /** 554 | * Set some Bored Apes aside 555 | * build 30 apes 556 | */ 557 | function reserveApes() public onlyOwner { 558 | uint supply = totalSupply(); 559 | uint i; 560 | for (i = 0; i < 30; i++) { 561 | _safeMint(msg.sender, supply + i); 562 | } 563 | } 564 | 565 | /** 566 | * DM Gargamel in Discord that you're standing right behind him. 567 | */ 568 | function setRevealTimestamp(uint256 revealTimeStamp) public onlyOwner { 569 | REVEAL_TIMESTAMP = revealTimeStamp; 570 | } 571 | 572 | /* 573 | * Set provenance once it's calculated 574 | */ 575 | function setProvenanceHash(string memory provenanceHash) public onlyOwner { 576 | BAYC_PROVENANCE = provenanceHash; 577 | } 578 | 579 | function setBaseURI(string memory baseURI) public onlyOwner { 580 | _setBaseURI(baseURI); 581 | } 582 | 583 | /* 584 | * Pause sale if active, make active if paused 585 | */ 586 | function flipSaleState() public onlyOwner { 587 | saleIsActive = !saleIsActive; 588 | } 589 | 590 | /** 591 | * Mints Bored Apes 592 | */ 593 | function mintApe(uint numberOfTokens) public payable { 594 | require(saleIsActive, "Sale must be active to mint Ape"); 595 | require(numberOfTokens <= maxApePurchase, "Can only mint 20 tokens at a time"); 596 | require(totalSupply().add(numberOfTokens) <= MAX_APES, "Purchase would exceed max supply of Apes"); 597 | require(apePrice.mul(numberOfTokens) <= msg.value, "Ether value sent is not correct"); 598 | 599 | for(uint i = 0; i < numberOfTokens; i++) { 600 | uint mintIndex = totalSupply(); 601 | if (totalSupply() < MAX_APES) { 602 | _safeMint(msg.sender, mintIndex); 603 | } 604 | } 605 | 606 | // If we haven't set the starting index and this is either 1) the last saleable token or 2) the first token to be sold after 607 | // the end of pre-sale, set the starting index block 608 | if (startingIndexBlock == 0 && (totalSupply() == MAX_APES || block.timestamp >= REVEAL_TIMESTAMP)) { 609 | startingIndexBlock = block.number; 610 | } 611 | } 612 | 613 | /** 614 | * Set the starting index for the collection 615 | */ 616 | function setStartingIndex() public { 617 | require(startingIndex == 0, "Starting index is already set"); 618 | require(startingIndexBlock != 0, "Starting index block must be set"); 619 | 620 | startingIndex = uint(blockhash(startingIndexBlock)) % MAX_APES; 621 | // Just a sanity case in the worst case if this function is called late (EVM only stores last 256 block hashes) 622 | if (block.number.sub(startingIndexBlock) > 255) { 623 | startingIndex = uint(blockhash(block.number - 1)) % MAX_APES; 624 | } 625 | // Prevent default sequence 626 | if (startingIndex == 0) { 627 | startingIndex = startingIndex.add(1); 628 | } 629 | } 630 | 631 | /** 632 | * Set the starting index block for the collection, essentially unblocking 633 | * setting starting index 634 | */ 635 | function emergencySetStartingIndexBlock() public onlyOwner { 636 | require(startingIndex == 0, "Starting index is already set"); 637 | 638 | startingIndexBlock = block.number; 639 | } 640 | } 641 | ``` 642 | 643 | 644 | 645 | 646 | 647 | We can see that the essence of NFT is to associate a blockchain account with a string. 648 | 649 | The author of BoredApeYachtClub first drew 30 pictures of monkeys, and then uploaded the pictures to a website to obtain a URL. 650 | 651 | Any purchase of NFT from them means that they will add a record that associates the URL corresponding to the picture with the buyer's address. 652 | 653 | Buyers then claim that they own the URL. 654 | 655 | Can other people get pictures through this URL? is allowed. Anyone can download this image and modify it. 656 | 657 | This is because the ownership of NFT is recorded on the blockchain, so the generation and transfer of NFT is absolutely clear, but the ownership of NFT is completely separated from the use value of NFT. 658 | 659 | Currently one of the cheapest monkeys is 70ETH, about $100,000. -------------------------------------------------------------------------------- /ethereum/solidity.md: -------------------------------------------------------------------------------- 1 | # Solidity 2 | 3 | 4 | 5 | ```solidity 6 | pragma solidity ^0.4.21; 7 | 8 | contract Coin { 9 | address public minter; 10 | mapping (address => uint) public balances; 11 | 12 | event Sent(address from, address to, uint amount); 13 | 14 | // when we create a contract, we call this. 15 | function Coin() public { 16 | minter = msg.sender; 17 | } 18 | 19 | // receiver and amount are from Calldata 20 | function mint(address receiver, uint amount) public { 21 | if (msg.sender != minter) return; 22 | balances[receiver] += amount; 23 | } 24 | 25 | function send(address receiver, uint amount) public { 26 | if (balances[msg.sender] < amount) return; 27 | balances[msg.sender] -= amount; 28 | balances[receiver] += amount; 29 | emit Sent(msg.sender, receiver, amount); 30 | } 31 | } 32 | ``` 33 | 34 | 1. When each smart contract is created, it will rely on a smart contract account. 35 | 36 | 2. Each smart contract account has a storage, which is a KV database. Minter and balances in the instance will enter it, and there is no clear maximum capacity limit for storage. 37 | 38 | 3. Every call to a smart contract function is equivalent to a transaction, and the transaction needs to be recorded in the block. The Ethereum blockchain can only produce one block at a time. This ensures orderliness. 39 | 40 | 4. Essentially any node can execute the function, which is concurrent. But only one execution result is recognized. 41 | 42 | 5. As long as it is a variable stored in storage, it can be obtained directly without executing the contract function. 43 | 44 | 6. Read-only Calldata changes the state of storage, which is the nature of most functions. 45 | 46 | 7. The payable function modifier enables Solidity contracts to accept payment in ether 47 | 48 | 8. When an error is reported in the middle of the execution of the function of the smart contract, the function state will automatically roll back to the state before the function execution to ensure that the state of the contract will not be modified to an invalid or inconsistent state. 49 | 50 | 51 | 52 | ### Global Variables 53 | 54 | There are many predefined global variables in Solidity, here are some common ones: 55 | 56 | 1. msg.sender - contains the address of the caller of the current function, used to verify the identity of the caller. 57 | 2. msg.value - Contains the amount of ether sent by the caller of the current function for receiving ether in the smart contract. 58 | 3. now - the timestamp of the current block (in seconds), which can be used to get the current time in the smart contract. 59 | 4. block.timestamp - the timestamp (in seconds) of the current block, same as the now variable. 60 | 5. block.number - the block number of the current block. 61 | 6. address(this) - the address of the current smart contract, used to refer to itself in the smart contract. 62 | 7. tx.origin - Contains the sender address of the transaction, not the address of the calling contract. Normally, tx.origin should not be used to authenticate the caller. 63 | 8. gasleft() - contains how much gas is left in the current transaction, which can be used to determine the gas usage of the current transaction in the smart contract. 64 | 65 | These global variables provide a convenient way to obtain various information in smart contracts, and can be used to write various types of smart contracts. However, they need to be used with care to avoid security holes and misbehavior. 66 | 67 | 68 | 69 | 70 | 71 | ### USDT 72 | 73 | 74 | 75 | ```solidity 76 | /** 77 | *Submitted for verification at Etherscan.io on 2017-11-28 78 | */ 79 | 80 | pragma solidity ^0.4.17; 81 | ``` 82 | 83 | The pragma instructs to use a specific version of Solidity. ^0.4.17 means to use 0.4.17 and all latest versions that are upwardly compatible with that version, such as 0.4.18, 0.4.19, etc. If you declare a version with the "^" symbol, the compiler will automatically select the latest version that is upwardly compatible with the current Solidity compiler version for compilation. 84 | 85 | ```solidity 86 | /** 87 | * @title SafeMath 88 | * @dev Math operations with safety checks that throw on error 89 | */ 90 | library SafeMath { 91 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 92 | if (a == 0) { 93 | return 0; 94 | } 95 | uint256 c = a * b; 96 | assert(c / a == b); 97 | return c; 98 | } 99 | 100 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 101 | // assert(b > 0); // Solidity automatically throws when dividing by 0 102 | uint256 c = a / b; 103 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 104 | return c; 105 | } 106 | 107 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 108 | assert(b <= a); 109 | return a - b; 110 | } 111 | 112 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 113 | uint256 c = a + b; 114 | assert(c >= a); 115 | return c; 116 | } 117 | } 118 | ``` 119 | 120 | 121 | 122 | - `library`: Indicates that this is a Solidity library (library), used to implement reusable code modules, be careful using other people's libraries. 123 | - `internal`: Indicates that this function can only be called inside the current contract or its inherited contracts, and cannot be called from outside the contract. 124 | - `pure`: Indicates that this function will not modify the state of the contract, and will not access the storage variables of the contract, nor will it interact with other contracts. 125 | - `returns`: indicates that this function will return one or more values. 126 | - `assert`: Indicates that if the function execution fails, an exception will be thrown (that is, the assertion failed) to terminate the program execution. 127 | 128 | 129 | 130 | 131 | 132 | ```solidity 133 | /** 134 | * @title Ownable 135 | * @dev The Ownable contract has an owner address, and provides basic authorization control 136 | * functions, this simplifies the implementation of "user permissions". 137 | */ 138 | contract Ownable { 139 | address public owner; 140 | 141 | /** 142 | * @dev The Ownable constructor sets the original `owner` of the contract to the sender 143 | * account. 144 | */ 145 | function Ownable() public { 146 | owner = msg.sender; 147 | } 148 | 149 | /** 150 | * @dev Throws if called by any account other than the owner. 151 | */ 152 | modifier onlyOwner() { 153 | require(msg.sender == owner); 154 | _; 155 | } 156 | 157 | /** 158 | * @dev Allows the current owner to transfer control of the contract to a newOwner. 159 | * @param newOwner The address to transfer ownership to. 160 | */ 161 | function transferOwnership(address newOwner) public onlyOwner { 162 | if (newOwner != address(0)) { 163 | owner = newOwner; 164 | } 165 | } 166 | 167 | } 168 | 169 | /** 170 | * @title Pausable 171 | * @dev Base contract which allows children to implement an emergency stop mechanism. 172 | */ 173 | contract Pausable is Ownable { 174 | event Pause(); 175 | event Unpause(); 176 | 177 | bool public paused = false; 178 | 179 | 180 | /** 181 | * @dev Modifier to make a function callable only when the contract is not paused. 182 | */ 183 | modifier whenNotPaused() { 184 | require(!paused); 185 | _; 186 | } 187 | 188 | /** 189 | * @dev Modifier to make a function callable only when the contract is paused. 190 | */ 191 | modifier whenPaused() { 192 | require(paused); 193 | _; 194 | } 195 | 196 | /** 197 | * @dev called by the owner to pause, triggers stopped state 198 | */ 199 | function pause() onlyOwner whenNotPaused public { 200 | paused = true; 201 | Pause(); 202 | } 203 | 204 | /** 205 | * @dev called by the owner to unpause, returns to normal state 206 | */ 207 | function unpause() onlyOwner whenPaused public { 208 | paused = false; 209 | Unpause(); 210 | } 211 | } 212 | ``` 213 | 214 | - `modifier` is used to define a reusable modifier function. A modifier is a special function that can be used to modify the behavior of a function, it can be added to the function definition to perform some logic checks or modifications on the function before or after the function is executed. Using modifiers can simplify your code, improve code readability, and reduce repetitive logic in your code. 215 | - `event` is a special type in Solidity used to trigger notifications inside smart contracts. Events are a lightweight communication mechanism for making notifications within smart contracts and providing data to external applications. An application can listen to events and perform some actions when the event is triggered. Events are often used to record important activities and state changes in smart contracts so that applications can respond to these changes. 216 | - `public` is a function access modifier in Solidity. Functions declared with the public keyword can be called by anyone, including addresses inside and outside the contract. State variables declared public can be read by anyone inside or outside the contract. It should be noted that public functions may affect the state of the contract, so security and logical correctness need to be carefully considered when writing public functions. 217 | - The underscore `_` is often used as a placeholder to denote the position of a function or modifier parameter. In the function or modifier definition, the position of the underscore `_` will be replaced by the actual parameter. For example, here's a simple example using underscores: 218 | - Require is an exception handling mechanism, which is used to check whether certain conditions are met during function execution. If the conditions are not met, the function execution is terminated and all states during the execution process are restored to the state before the function call. ` 219 | - The is keyword is used to indicate inheritance 220 | 221 | 222 | 223 | 224 | 225 | ```solidity 226 | 227 | /** 228 | * @title ERC20Basic 229 | * @dev Simpler version of ERC20 interface 230 | * @dev see https://github.com/ethereum/EIPs/issues/20 231 | */ 232 | contract ERC20Basic { 233 | uint public _totalSupply; 234 | function totalSupply() public constant returns (uint); 235 | function balanceOf(address who) public constant returns (uint); 236 | function transfer(address to, uint value) public; 237 | event Transfer(address indexed from, address indexed to, uint value); 238 | } 239 | 240 | /** 241 | * @title ERC20 interface 242 | * @dev see https://github.com/ethereum/EIPs/issues/20 243 | */ 244 | contract ERC20 is ERC20Basic { 245 | function allowance(address owner, address spender) public constant returns (uint); 246 | function transferFrom(address from, address to, uint value) public; 247 | function approve(address spender, uint value) public; 248 | event Approval(address indexed owner, address indexed spender, uint value); 249 | } 250 | 251 | /** 252 | * @title Basic token 253 | * @dev Basic version of StandardToken, with no allowances. 254 | */ 255 | contract BasicToken is Ownable, ERC20Basic { 256 | using SafeMath for uint; 257 | 258 | mapping(address => uint) public balances; 259 | 260 | // additional variables for use if transaction fees ever became necessary 261 | uint public basisPointsRate = 0; 262 | uint public maximumFee = 0; 263 | 264 | /** 265 | * @dev Fix for the ERC20 short address attack. 266 | */ 267 | modifier onlyPayloadSize(uint size) { 268 | require(!(msg.data.length < size + 4)); 269 | _; 270 | } 271 | 272 | /** 273 | * @dev transfer token for a specified address 274 | * @param _to The address to transfer to. 275 | * @param _value The amount to be transferred. 276 | */ 277 | function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) { 278 | uint fee = (_value.mul(basisPointsRate)).div(10000); 279 | if (fee > maximumFee) { 280 | fee = maximumFee; 281 | } 282 | uint sendAmount = _value.sub(fee); 283 | balances[msg.sender] = balances[msg.sender].sub(_value); 284 | balances[_to] = balances[_to].add(sendAmount); 285 | if (fee > 0) { 286 | balances[owner] = balances[owner].add(fee); 287 | Transfer(msg.sender, owner, fee); 288 | } 289 | Transfer(msg.sender, _to, sendAmount); 290 | } 291 | 292 | /** 293 | * @dev Gets the balance of the specified address. 294 | * @param _owner The address to query the the balance of. 295 | * @return An uint representing the amount owned by the passed address. 296 | */ 297 | function balanceOf(address _owner) public constant returns (uint balance) { 298 | return balances[_owner]; 299 | } 300 | 301 | } 302 | 303 | /** 304 | * @title Standard ERC20 token 305 | * 306 | * @dev Implementation of the basic standard token. 307 | * @dev https://github.com/ethereum/EIPs/issues/20 308 | * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol 309 | */ 310 | contract StandardToken is BasicToken, ERC20 { 311 | 312 | mapping (address => mapping (address => uint)) public allowed; 313 | 314 | uint public constant MAX_UINT = 2**256 - 1; 315 | 316 | /** 317 | * @dev Transfer tokens from one address to another 318 | * @param _from address The address which you want to send tokens from 319 | * @param _to address The address which you want to transfer to 320 | * @param _value uint the amount of tokens to be transferred 321 | */ 322 | function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) { 323 | var _allowance = allowed[_from][msg.sender]; 324 | 325 | // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met 326 | // if (_value > _allowance) throw; 327 | 328 | uint fee = (_value.mul(basisPointsRate)).div(10000); 329 | if (fee > maximumFee) { 330 | fee = maximumFee; 331 | } 332 | if (_allowance < MAX_UINT) { 333 | allowed[_from][msg.sender] = _allowance.sub(_value); 334 | } 335 | uint sendAmount = _value.sub(fee); 336 | balances[_from] = balances[_from].sub(_value); 337 | balances[_to] = balances[_to].add(sendAmount); 338 | if (fee > 0) { 339 | balances[owner] = balances[owner].add(fee); 340 | Transfer(_from, owner, fee); 341 | } 342 | Transfer(_from, _to, sendAmount); 343 | } 344 | 345 | /** 346 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 347 | * @param _spender The address which will spend the funds. 348 | * @param _value The amount of tokens to be spent. 349 | */ 350 | function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) { 351 | 352 | // To change the approve amount you first have to reduce the addresses` 353 | // allowance to zero by calling `approve(_spender, 0)` if it is not 354 | // already 0 to mitigate the race condition described here: 355 | // https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 356 | require(!((_value != 0) && (allowed[msg.sender][_spender] != 0))); 357 | 358 | allowed[msg.sender][_spender] = _value; 359 | Approval(msg.sender, _spender, _value); 360 | } 361 | 362 | /** 363 | * @dev Function to check the amount of tokens than an owner allowed to a spender. 364 | * @param _owner address The address which owns the funds. 365 | * @param _spender address The address which will spend the funds. 366 | * @return A uint specifying the amount of tokens still available for the spender. 367 | */ 368 | function allowance(address _owner, address _spender) public constant returns (uint remaining) { 369 | return allowed[_owner][_spender]; 370 | } 371 | 372 | } 373 | 374 | contract UpgradedStandardToken is StandardToken{ 375 | // those methods are called by the legacy contract 376 | // and they must ensure msg.sender to be the contract address 377 | function transferByLegacy(address from, address to, uint value) public; 378 | function transferFromByLegacy(address sender, address from, address spender, uint value) public; 379 | function approveByLegacy(address from, address spender, uint value) public; 380 | } 381 | ``` 382 | 383 | In Solidity, when defining a function, you can first declare information such as the name, parameters, and return value type of the function, without having to implement the function body immediately. Such a function is called a function signature (Function Signature). 384 | 385 | The `using SafeMath for uint;` statement is used to apply the safe math functions in the `SafeMath` library to the data of type `uint`. This means that in `uint` type data, you can use `add`, `sub`, `mul`, `div` and other safe mathematical operation functions instead of native operators, so as to prevent mathematical overflow or underflow, etc. question. 386 | 387 | In Solidity, `msg.sender` is a global variable that represents the address of the account that calls the current contract function. In Ethereum, each transaction has a sender (Sender), `msg.sender` is the sender address of the current transaction. 388 | 389 | `msg.sender` can be used to verify whether the user calling the contract function has the permission to execute the function. For example, if the contract function only allows the owner of the contract to execute, you can use `require(msg.sender == owner)` inside the function to verify whether the caller is the owner of the contract, and if not, an exception will be thrown, Function execution terminates. 390 | 391 | 392 | 393 | Suppose A wants to trade with B, and the exchange is C, then the transaction process is roughly as follows: 394 | 395 | 1. A submits an order to buy tokens on exchange C. 396 | 2. C generates a new order number and requests A to authorize the token transfer. 397 | 3. A calls the `approve` function of the token contract it holds, and authorizes a certain amount of tokens to C, so that C can transfer tokens on behalf of A. 398 | 4. A sends the authorized order number and related information to C. 399 | 5. B submits an order to sell tokens on exchange C. 400 | 6. C generates a new order number and requests token transfer from B. 401 | 7. B calls the `approve` function of the token contract it holds, and authorizes a certain amount of tokens to C, so that C can transfer tokens on behalf of B. 402 | 8. B sends the authorized order number and related information to C. 403 | 9. C calls the `transferFrom` function of the token contract according to the order number and authorization information, transfers the token from account A to account B, and draws a certain percentage of handling fees. 404 | 10. C updates the order status and notifies A and B that the order has been completed. 405 | 406 | In this transaction process, both A and B need to call the `approve` function to authorize C to transfer tokens on their behalf. C needs to call the `transferFrom` function to realize the token transfer and extract the handling fee. Since the proxy account can only call the `transferFrom` function after being authorized, the security and trustworthiness of the token transfer process can be ensured. 407 | 408 | 409 | 410 | Note that this means that C is trusted. 411 | 412 | ```solidity 413 | contract BlackList is Ownable, BasicToken { 414 | 415 | /////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) /////// 416 | function getBlackListStatus(address _maker) external constant returns (bool) { 417 | return isBlackListed[_maker]; 418 | } 419 | 420 | function getOwner() external constant returns (address) { 421 | return owner; 422 | } 423 | 424 | mapping (address => bool) public isBlackListed; 425 | 426 | function addBlackList (address _evilUser) public onlyOwner { 427 | isBlackListed[_evilUser] = true; 428 | AddedBlackList(_evilUser); 429 | } 430 | 431 | function removeBlackList (address _clearedUser) public onlyOwner { 432 | isBlackListed[_clearedUser] = false; 433 | RemovedBlackList(_clearedUser); 434 | } 435 | 436 | function destroyBlackFunds (address _blackListedUser) public onlyOwner { 437 | require(isBlackListed[_blackListedUser]); 438 | uint dirtyFunds = balanceOf(_blackListedUser); 439 | balances[_blackListedUser] = 0; 440 | _totalSupply -= dirtyFunds; 441 | DestroyedBlackFunds(_blackListedUser, dirtyFunds); 442 | } 443 | 444 | event DestroyedBlackFunds(address _blackListedUser, uint _balance); 445 | 446 | event AddedBlackList(address _user); 447 | 448 | event RemovedBlackList(address _user); 449 | 450 | } 451 | ``` 452 | 453 | - `external`: Indicates that the function can only be called from outside the contract, not inside the contract. Usually used in public functions to provide the external interface of the contract. 454 | - `constant`: Indicates that the function will not modify the state variables of the contract, nor will it generate any transaction fees, but just read the value of the contract state and return it. Such functions are also often referred to as "view functions" or "pure functions". 455 | 456 | In Solidity, `external` and `constant` can modify a function at the same time, indicating that the function is not only a function that can only be called from outside the contract, but also a pure function that does not modify the state of the contract. This kind of function is usually used to query the value of the contract state without modifying the state. 457 | 458 | Annotating a function helps the compiler with code optimization and error checking, but it doesn't affect the actual gas cost. When you call a function in a contract, you need to pay the gas fee for the function to execute, regardless of whether the function is marked or not. 459 | 460 | 461 | 462 | 463 | 464 | ```solidity 465 | contract TetherToken is Pausable, StandardToken, BlackList { 466 | 467 | string public name; 468 | string public symbol; 469 | uint public decimals; 470 | address public upgradedAddress; 471 | bool public deprecated; 472 | 473 | // The contract can be initialized with a number of tokens 474 | // All the tokens are deposited to the owner address 475 | // 476 | // @param _balance Initial supply of the contract 477 | // @param _name Token Name 478 | // @param _symbol Token symbol 479 | // @param _decimals Token decimals 480 | function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public { 481 | _totalSupply = _initialSupply; 482 | name = _name; 483 | symbol = _symbol; 484 | decimals = _decimals; 485 | balances[owner] = _initialSupply; 486 | deprecated = false; 487 | } 488 | 489 | // Forward ERC20 methods to upgraded contract if this one is deprecated 490 | function transfer(address _to, uint _value) public whenNotPaused { 491 | require(!isBlackListed[msg.sender]); 492 | if (deprecated) { 493 | return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value); 494 | } else { 495 | return super.transfer(_to, _value); 496 | } 497 | } 498 | 499 | // Forward ERC20 methods to upgraded contract if this one is deprecated 500 | function transferFrom(address _from, address _to, uint _value) public whenNotPaused { 501 | require(!isBlackListed[_from]); 502 | if (deprecated) { 503 | return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value); 504 | } else { 505 | return super.transferFrom(_from, _to, _value); 506 | } 507 | } 508 | 509 | // Forward ERC20 methods to upgraded contract if this one is deprecated 510 | function balanceOf(address who) public constant returns (uint) { 511 | if (deprecated) { 512 | return UpgradedStandardToken(upgradedAddress).balanceOf(who); 513 | } else { 514 | return super.balanceOf(who); 515 | } 516 | } 517 | 518 | // Forward ERC20 methods to upgraded contract if this one is deprecated 519 | function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) { 520 | if (deprecated) { 521 | return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value); 522 | } else { 523 | return super.approve(_spender, _value); 524 | } 525 | } 526 | 527 | // Forward ERC20 methods to upgraded contract if this one is deprecated 528 | function allowance(address _owner, address _spender) public constant returns (uint remaining) { 529 | if (deprecated) { 530 | return StandardToken(upgradedAddress).allowance(_owner, _spender); 531 | } else { 532 | return super.allowance(_owner, _spender); 533 | } 534 | } 535 | 536 | // deprecate current contract in favour of a new one 537 | function deprecate(address _upgradedAddress) public onlyOwner { 538 | deprecated = true; 539 | upgradedAddress = _upgradedAddress; 540 | Deprecate(_upgradedAddress); 541 | } 542 | 543 | // deprecate current contract if favour of a new one 544 | function totalSupply() public constant returns (uint) { 545 | if (deprecated) { 546 | return StandardToken(upgradedAddress).totalSupply(); 547 | } else { 548 | return _totalSupply; 549 | } 550 | } 551 | 552 | // Issue a new amount of tokens 553 | // these tokens are deposited into the owner address 554 | // 555 | // @param _amount Number of tokens to be issued 556 | function issue(uint amount) public onlyOwner { 557 | require(_totalSupply + amount > _totalSupply); 558 | require(balances[owner] + amount > balances[owner]); 559 | 560 | balances[owner] += amount; 561 | _totalSupply += amount; 562 | Issue(amount); 563 | } 564 | 565 | // Redeem tokens. 566 | // These tokens are withdrawn from the owner address 567 | // if the balance must be enough to cover the redeem 568 | // or the call will fail. 569 | // @param _amount Number of tokens to be issued 570 | function redeem(uint amount) public onlyOwner { 571 | require(_totalSupply >= amount); 572 | require(balances[owner] >= amount); 573 | 574 | _totalSupply -= amount; 575 | balances[owner] -= amount; 576 | Redeem(amount); 577 | } 578 | 579 | function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner { 580 | // Ensure transparency by hardcoding limit beyond which fees can never be added 581 | require(newBasisPoints < 20); 582 | require(newMaxFee < 50); 583 | 584 | basisPointsRate = newBasisPoints; 585 | maximumFee = newMaxFee.mul(10**decimals); 586 | 587 | Params(basisPointsRate, maximumFee); 588 | } 589 | 590 | // Called when new token are issued 591 | event Issue(uint amount); 592 | 593 | // Called when tokens are redeemed 594 | event Redeem(uint amount); 595 | 596 | // Called when contract is deprecated 597 | event Deprecate(address newAddress); 598 | 599 | // Called if contract ever adds fees 600 | event Params(uint feeBasisPoints, uint maxFee); 601 | } 602 | ``` --------------------------------------------------------------------------------