pm2配置Payroll记录
1 | cd Payroll |
种瓜得瓜 种豆得豆
1 | npm install -g truffle |
Error: Cannot find module ‘scrypt’
解决办法:npm install scrypt
无法识别的命令行选项“-std=c++11
解决办法:升级gcc
/usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.21’ not found
解决办法:
1 | [root@iZuf6h7yd9haonvv70i74oZ Payroll]# cp /usr/local/lib/libstdc++.so.6.0.21 /usr/lib/ |
阿里云主机的自带gcc版本都比较低,在编译一些稍微比较比较新的库时,会报出如下错误:
无法识别的命令行选项“-std=c++11
查找之后得知需要升级gcc至4.8版本以上,遂决定手动升级gcc。
查看当前版本:
1 | [root@iZuf6h7yd9haonvv70i74oZ ~]# gcc --version |
镜像下载地址:gcc.skazkaforyou.com
或者 gcc官网
我选择了5.2版本的下载:
1 | wget http://gcc.skazkaforyou.com/releases/gcc-5.2.0/gcc-5.2.0.tar.bz2 |
下载文件大小在100M左右,如果遇到下载慢的,可以尝试更换其他下载镜像地址。
1 | tar -xf gcc-5.2.0.tar.bz2 |
1 | cd gcc-5.2.0 |
1 | mkdir build_temp |
等待大概一个小时以后,make完成,执行安装命令。
1 | make install |
查看安装的gcc,默认安装目录在usr/local/bin
1 | [root@iZuf6h7yd9haonvv70i74oZ build_temp]# ls /usr/local/bin | grep gcc |
执行升级命令
1 | /usr/sbin/update-alternatives --install /usr/bin/gcc gcc /usr/local/bin/i686-pc-linux-gnu-gcc-5.2.0 52 |
重新连接上服务器,打开终端,执行如下命令:
1 | [root@iZuf6h7yd9haonvv70i74oZ ~]# gcc --version |
1 | mkdir ETHWalletGenerator |
1 | npm install secp256k1 |
1 | 'use strict'; |
1 | node ethGenerator.js |
之前跟着公众号文章在个人私有链上发布过ERC20 的Token合约,当时稀里糊涂的,代码也没有细看,最近在做Solidity代码相关的复习,上次上完培训课之后都有点遗忘了,借此机会,整理一下ERC20 Token相关的知识点,以备以后使用。
EIPs/eip-20.md at master · ethereum/EIPs · GitHub
标准的内容比较简单,英文不算生僻,此处不再全部翻译,着重记录几个点。
可选,返回token的名称,例如“TedToken”。function name() view returns (string name)
可选,返回token的符号,比如“TEC”。function symbol() view returns (string symbol)
可选,返回token的精确小数点,通用是18。function decimals() view returns (uint8 decimals)
全部供应量,也就是发行量。function totalSupply() view returns (uint256 totalSupply)
查询余额,返回指定address的余额function balanceOf(address _owner) view returns (uint256 balance)
发送token,发送指定数目的token到指定账户,必须触发Transfer事件。如果余额不足,必须throw异常。另外,即使转账0个token,也必须向非0转账那样触发Transfer事件。
一般是owner向其他人发送代币。function transfer(address _to, uint256 _value) returns (bool success)
交易token,从一个地址向另外一个地址转账指定额度的token,必须触发Transfer事件,这个方法可以理解为一个收款流程,允许合约来代表token持有者发送代币。比如,合约可以帮助你向另外一个人发送token或者索要token。前提是token拥有者必须要通过某些机制对这个请求进行确认,比如通过MetaMask进行confirm。否则,执行将失败。
跟transfer一样,即使发送0代币,也要触发Transfer事件。function transferFrom(address _from, address _to, uint256 _value) returns (bool success)
批准额度,允许一个账户最多能从你的账户你取现指定额度。重复调用时,以最后一次的额度为主。为了防止攻击,最开始这个额度必须设置为0。function approve(address _spender, uint256 _value) returns (bool success)
跟approve对应,获得指定用户的批准额度。function allowance(address _owner, address _spender) view returns (uint256 remaining)
任何token发送发生时,必须触发该事件,即使是0额度。
当一个token合约创建时,应该触发一个Transfer事件,token的发送方是0x0,也就是说凭空而来的token,简称空气币。event Transfer(address indexed _from, address indexed _to, uint256 _value)
当approve被调用时,需要触发该事件。event Approval(address indexed _owner, address indexed _spender, uint256 _value)
官方源码:Tokens/EIP20.sol at master · ConsenSys/Tokens · GitHub 我的源码:GitHub - xiongwei-git/Tokens: One EIP-20 Token Sample
这个示例源码比较简单,包含三个sol文件,分别是接口定义EIP20Interface,Token实现EIP20和Token管理类EIP20Factory。
1 | contract EIP20Interface { |
1 | import "./EIP20Interface.sol"; |
1 | import "./EIP20.sol"; |
openzeppelin-solidity/contracts/token/ERC20 at master · OpenZeppelin/openzeppelin-solidity · GitHub
学习Solidity语言的时候,通过多重继承接触到了C3线性化的概念,整理一篇文章记录下相关知识点。
在支持多重继承的语言中,比如python、solidity等,如果出现了一个类有多重继承的情况,如下Python代码:
1 | #!/usr/bin/python |
就会出现一个问题,如果我调用Z中的某个父类方法时,该去调用哪个父类呢?子类往上寻找父类方法的顺序是什么?
C3线性化,也叫方法解析顺序(Method Resolution Order,MRO),是一种用于在多继承时确定继承的方法的调用顺序的算法。
至于为什么叫C3,主要是因为最终线性化的三种重要特性:
也就是说通过C3算法将多重继承的树状结构继承关系实现线性化,生成一个线性序列,确定了子类查找父类方法的优先顺序。
关于C3算法的规则,我们先看分别引用三个地方不同的解释:
引用维基百科-C3线性化
一个类的C3超类线性化是这个类,再加上它的各个父类的线性化与各个父类形成列表的唯一合并的结果。 父类列表作为合并过程的最后实参,保持了直接父类的本地前趋序。
各个父类的线性化与各个父类形成列表的合并算法,首先选择不出现在各个列表的尾部(指除了第一个元素外的其他元素)的第一个元素,该元素可能同时出现在多个列表的头部。被选中元素从各个列表中删除并追加到输出列表中。这个选择再删除、追加元素的过程迭代下去直到各个列表被耗尽。如果在某个时候无法选出元素,说明这个类继承体系的依赖序是不一致的,因而无法线性化。
引用《Python高级编程》
引用网络文章-python多重继承新算法C3
如果继承至一个基类:
class B(A)
这时B的mro序列为[B,A]
如果继承至多个基类
class B(A1,A2,A3 …)
这时B的mro序列 mro(B) = [B] + merge(mro(A1), mro(A2), mro(A3) …, [A1,A2,A3])
merge操作就是C3算法的核心。
遍历执行merge操作的序列,如果一个序列的第一个元素,是其他序列中的第一个元素,或不在其他序列出现,则从所有执行merge操作序列中删除这个元素,合并到当前的mro中。
merge操作后的序列,继续执行merge操作,直到merge操作的序列为空。
如果merge操作的序列无法为空,则说明不合法。
再回到最开始的Python代码中的多继承关系,梳理如下:
O
A -> O
B -> O
C -> O
K1 -> B, A
K2 -> C, A
Z -> K2, K1
我们的目标是确定Z的父类方法调用顺序
开始按照C3算法计算,核心点在于从Merge的序列中取出合适的元素,放入到当前的Mro序列中,直到Merge序列为空为止。
1 | L(O) := [O] |
那么结论就是Z类的父类方法调用顺序为Z, K2, C, K1, B, A, O
在Python中,使用mro属性来存储当前类的方法解析顺序,我们可以在最初的Python代码最后面加入一行
1 | print Z.__mro__ |
然后执行这段Python即可看到结果:
1 | $ npm install -g ganache-cli truffle |
1 | $ testrpc |
新开一个终端窗口,通过以下命令建立项目:
1 | ted@MacBook-Pro ~ mkdir SmartContact |
需要对目录结构做一个解释说明:/contracts
: 存放智能合约原始代码的地方,可以看到里面已经有一个sol文件。/migrations
: 这是 Truffle
用来部署智能合约的功能。/test
: 测试智能合约的代码。truffle.js
: Truffle
的设置文件。
在contracts
文件夹中创建HelloWorld.sol
文件,内容如下:
1 | pragma solidity ^0.4.4; |
在项目的目录下执行truffle compile
命令,将sol
文件编译成Ethereum bytecode
1 | ted@MacBook-Pro ~/SmartContract/HelloWorld truffle compile |
在migrations
文件夹中已经存在一个配置文件,1_initial_migration.js
,仿照这个文件新建一个2_deploy_contracts.js
,内容如下:
1 | var HelloWorld = artifacts.require("HelloWorld"); |
在命令行中执行truffle migrate
开始部署,可能会遇到以下问题:
问题1:no-network-specified-cannot-determine-current network
解决办法是在`HelloWorld/truffle.js·文件中添加以下内容:
1 | module.exports = { |
如果没有问题,顺利执行之后,智能合约即可部署成功
1 | ted@MacBook-Pro ~/SmartContract/HelloWorld truffle migrate |
于此同时testrpc
的窗口也有一些内容输出:
通过命令truffle console
进入truffle控制台,即可使用Javascript
调用刚才部署的合约。
1 | ted@MacBook-Pro ~/SmartContract/HelloWorld truffle console |
需要解释一段代码
1 | HelloWorld.deployed().then(instance => contract = instance) |
·truffle console中预载了
truffle-contract`函数库,以方便操作部署到区块链上的合约。
这边使用HelloWorld.deployed().then
语句来取得HelloWorld
合约的Instance
(实例),并存到contract
变量中,以方便后续的调用。
上面用的是Javascript ES6+
的语法,这句也可以写成:
1 | HelloWorld.deployed().then(instance => { |
还可以用ES5的写法:
1 | HelloWorld.deployed().then(function(instance) { |
这里直接呼叫contract.sayHello()
也会得到一样的结果。truffle-contract
提供使用call()
来读取只读(read only)的数据,这样就不需提供gas
。因此如果遇到的操作需要向区块链写入数据,我们就不能用call
语句了。
最后在truffle console
中输入.exit
即可退出控制台回到终端页面。
1 | geth --datadir data --networkid 12 --rpc --rpccorsdomain "*" --port 33040 console |
1 | open -a /Applications/Mist.app --args --rpc /Users/ted/Private/data/geth.ipc |
启动页面右上角显示PRIVATE-NET字样,代表连接成功
连接上之后,需要一个矿工挖矿才能开始同步信息
基于macOS High Sierra安装,系统版本 10.13.2
brew -v
即可检查,如果没有安装,则去官网查看如何安装brew tap ethereum/ethereum
brew install ethereum
geth -h
,如果显示如下内容说明安装成功npm -v
即可检查,如果没有安装,通过brew intall node
安装完成node之后,npm也安装成功npm install -g solc
安装solcsolc --help
检查是否安装成功,如果提示找不到命令,可尝试使用npm install -g solc solc-cli --save-dev
来取代上一条命令安装solc,如果显示如下内容,代表安装成功新建文件夹,命名为TedEth(随意命名),在文件夹下创建genesis.json和data文件夹。genesis.json文件内容如下:
1 | { |
解释一下各个参数的含义:
字段 | 含义 |
---|---|
mixhash | 与nonce配合用于挖矿,由上一个区块的一部分生成的hash。注意他和nonce的设置需要满足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。 |
nonce | nonce就是一个64位随机数,用于挖矿 |
difficulty | 设置当前区块的难度,如果难度过大,cpu挖矿就很难,这里设置较小难度 |
alloc | 用来预置账号以及账号的以太币数量,因为私有链挖矿比较容易,所以我们不需要预置有币的账号,需要的时候自己创建即可以。 |
coinbase | 矿工的账号,随便填 |
timestamp | 设置创世块的时间戳 |
parentHash | 上一个区块的hash值,因为是创世块,所以这个值是0 |
extraData | 附加信息,随便填,可以填你的个性信息,内容必须0x开头,16进制内容 |
gasLimit | 该值设置对GAS的消耗总量限制,用来限制区块能包含的交易信息总和,因为我们是私有链,所以填最大 |
在命令行中进入刚才创建的TedEth文件夹,然后执行如下命令:geth --datadir data init genesis.json
各参数代表的含义如下:
字段 | 含义 |
---|---|
init | 表示初始化区块,后面跟着创世块的配置文件genesis.json |
datadir | 数据存放的位置 |
命令执行之后输出如下结果:
geth --datadir data --networkid 123456 --rpc --rpccorsdomain "*" --nodiscover console
各参数代表的含义如下:
字段 | 含义 |
---|---|
identity | 区块链的标示,随便填写,用于标示目前网络的名字 |
port | 网络监听端口 |
rpc | 启动rpc通信,可以进行智能合约的部署和调试 |
rpcapi | 设置允许连接的rpc的客户端,一般为db,eth,net,web3,默认情况下,Geth允许web3 |
networkid | 设置当前区块链的网络ID,用于区分不同的网络,是一个数字 |
console | 启动命令行模式,可以在Geth中执行命令 |
rpccorsdomain | 设置请求ip白名单 * 为所有 |
nodiscover | 使用这个参数,你的节点就不会被其他人发现,除非手动添加你的节点。否则,就只有一个被无意添加到一个陌生区块链上的机会,那就是跟你有相同的genesis文件和networkID。 |
执行成功后将进入区块链的JavaScript控制台环境
创建新账号 personal.newAccount()
或者 personal.newAccount("123456")
查看节点信息 admin.nodeInfo
挖矿 开始挖矿 miner.start(1)
停止挖矿 miner.stop()
查看当前矿工账号 eth.coinbase
默认为第一个账户
修改矿工账号 miner.setEtherbase(eth.accounts[1])
查看账户信息 eth.accounts[0]
查看账户余额 eth.getBalance(eth.accounts[0])
或者 web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
解锁账号 personal.unlockAccount(eth.accounts[0])
使用账户资金前都需要先解锁账号
转账 eth.sendTransaction({from:eth.accounts[0],to:"0x587e57a516730381958f86703b1f8e970ff445d9",value:web3.toWei(3,"ether")})
使用 txpool.status
可以看到交易状态
查看区块数据 eth.blockNumber
eth.getTransaction("0x0c59f431068937cbe9e230483bc79f59bd7146edc8ff5ec37fea6710adcab825")
eth.getBlock(1)
通过区块号查看区块
1 | > personal.newAccount() //创建A账户 |