小王同学 - 区块链
https://feelncut.com/category/blockChain/
区块链技术
-
ETH 2.0 资源汇总(持续更新)
https://feelncut.com/2020/08/24/323.html
2020-08-24T11:06:00+08:00
## 0 概述
本文整理总结了 ETH 2.0 学习、研究的常用资源,持续更新中。
ETH 2.0 整体介绍:https://hackernoon.com/what-to-expect-when-eths-expecting-80cb4951afcd
国内社区翻译版本:https://www.odaily.com/post/5135663
![](/images/2020/08/1751595903.png)
目前,ETH 2.0 已经启动了 Phase 0 测试网,可以通过质押 GöETH 成为验证节点。
[...]
-
ETH 2.0 测试网验证节点质押流程体验
https://feelncut.com/2020/08/24/322.html
2020-08-24T10:41:00+08:00
## 0 概述
本文记录了 ETH 2.0 测试网验证节点质押流程。
[...]
-
如何开发一款区块链浏览器?
https://feelncut.com/2020/05/20/308.html
2020-05-20T16:29:00+08:00
## 摘要
步入币圈大门后,除了钱包应用之外,用户最先接触的应该还有区块链浏览器。区块链浏览器不同于电脑和手机上浏览网页用的浏览器软件,而是指一个网站可以查询区块链上的具体信息。比如,给定区块高度,可以查询该高度区块的创建时间,包含了多少交易;给定一个地址,可以查询余额,该地址的所有交易记录等。当前以太坊上的数据量级已达亿级,如何进行数据持久化和查询呢?本文以以太坊为例,对区块链浏览器原理及存储细节进行分析总结。
[...]
-
EOS 提交交易失败分析
https://feelncut.com/2020/02/02/288.html
2020-02-02T12:53:00+08:00
[TOC]
EOS 向节点提交交易时失败,提示 billed CPU time (Y us) is greater than the maximum billable CPU time for the transaction (X us).
本文通过分析源代码来一探这个失败的原因,首先给出结论:
- 当前时间窗口内(24小时)用户**最大** CPU 时间 = 全网总 CPU 时间 * 当前用户质押 EOS 数量 / 所有用户质押 EOS 数量
- 当前时间窗口内用户**可用** CPU 时间 = 当前用户**最大** CPU 时间 - 当前用户已经使用 CPU 时间
- 当前用户**已经使用** CPU 时间是实时变化的:(1 - t / 24) * t 时间之前使用的资源大小,直到距离上次 CPU 资源使用 24 小时后(t = 24)完全恢复
- Get Account 接口看到的不是实时可用的资源使用量,而是上一笔交易之后缓存的资源使用量
- 向 RPC 节点提交交易时 RPC 节点会计算出当前交易 CPU 使用量,这个 CPU 使用量和当前 RPC 节点 CPU 使用情况有关,通过系统计时器计算时间,因此,RPC 节点计算出的交易 CPU 使用量不是最终上链时的交易使用量,最终交易时的 CPU 使用量由打包节点决定。
- 因此,当质押 CPU EOS 数量固定时,向 RPC 节点提交交易时,CPU 资源需要满足 交易使用 CPU 资源的大小 [...]
-
以太坊多重签名原理分析
https://feelncut.com/2018/10/17/228.html
2018-10-17T01:54:00+08:00
## 目录
[TOC]
## 0 起源与现状
一般来说一个以太坊地址对应一个私钥,动用这个地址中的资金需要私钥的掌握者发起签名才行。消费这笔资金时,所构造的签名交易被称为“单签名交易”。
而多重签名技术,简单来说,一个以太坊地址对应多个私钥,就是动用一笔资金时需要多个私钥签名才有效。消费这笔资金时,所构造的签名交易被称为“多签名交易”,或者“M-of-N 交易”,对应的比特币地址被称为“多签地址”。
目前,在以太坊中常用的多签钱包有:
- [Mist](https://github.com/ethereum/mist) 以太坊官方维护的钱包,支持多签
- [Ethereum Wallet](https://www.ethereum.org/) 以太坊官方维护的钱包,支持多签
- [Parity](https://github.com/paritytech/parity-ethereum) 支持多签
在以太坊中,多签钱包全部都是通过智能合约实现,下面介绍以太坊中的多签实现原理,实例分析。
[...]
-
Python3 中 AES256对称加密解密以及RSA2048签名验签
https://feelncut.com/2018/08/06/170.html
2018-08-06T14:03:00+08:00
# ETH相关流程
## ETH地址转换
调用`get_key`接口传入私钥`name`和`version`可获取私钥公开部分信息。
将获取私钥公开部分中X与Y合并为一个数组,长度为64字节,经`keccak_256`算法计算hash得到32字节hash,取后20字节,即为以太坊钱包地址。
```python
key_bundle = client.get_key('https://wangke-test-k-v.vault.azure.net/', 'x', 'x')
full_pubkey = key_bundle.key.x + key_bundle.key.y
import sha3
k = sha3.keccak_256()
k.update(full_pubkey)
print(k.hexdigest())
print('0x' + k.hexdigest()[24:])
```
公钥中是否需要加前缀`0x04`需要进一步验证。
## ETH交易签名
### 交易签名流程
ETH`未签名交易信息`包含了:
- nonce
- gasPrice
- gas
- value
- to
- data
- chainId
交易签名指:将以上未签名交易信息按照以太坊`RLP`规则序列化得到`rawTransaction`,`rawTransaction`再经过`keccak`得到`hash`,对该`hash`使用私钥进行签名,签名结果包含`R,S,V`三个部分。
再以上未签名交易信息中增加`R,S,V`得到`签名交易信息`:
- nonce
- gasPrice
- gas
- value
- to
- data
- chainId
- r
- s
- v
将签名交易信息按照以太坊`RLP`规则序列化得到`rawSignedTransaction`,此`rawSignedTransaction`可使用`web3`接口`sendRawTransaction`直接发送。对此`rawSignedTransaction`进行`keccak`得到交易hash:`txhash`。
### 使用KV签名
根据交易签名流程可知,只需要将`rawTransaction`经过`keccak`得到的`hash`传入服务端,服务端调用KV的`sign`接口对其进行签名。`sign`接口返回的结果只包含`R,S`,根据公钥信息可计算出`V`。服务端返回`R,S,V`,客户端根据`R,S,V`得到`rawSignedTransaction`。
计算`V`的算法如下:
```python
from coincurve import PublicKey
for v in range(4):
print(bytes([v]))
s = s_res.result + bytes([v])
try:
public_key_bytes = PublicKey.from_signature_and_message(s, bytes.fromhex(raw), hasher=None).format(compressed=False)
print(public_key_bytes==pk)
except:
print('error')
```
### EIP155
根据[EIP155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md "BIP155")规则:
- 如果`未签名交易信息`中包含`chainId`,则还应包含`r=0,s=0`,签名得到的`v`需要经过`v = v + CHAIN_ID_OFFSET + 2 * chain_id`变换,`CHAIN_ID_OFFSET`为`35`。此时交易只在对应`chain_id`的链上有效。
- 如果`未签名交易信息`中不包含`chainId`,签名得到的`v`需要经过`v = v_raw + V_OFFSET`变换,`V_OFFSET`为`27`。此时交易在所有链上有效。(正式链,几个不同的测试链)
# AES256加密解密
使用依赖`pip3 install pycrypto`。
测试代码:
```python
from Crypto.Cipher import AES
from Crypto import Random
import base64
BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
unpad = lambda s : s[0:-s[-1]]
# bkey可以是16, 24 或 32 位长度, 其对应 AES-128, AES-196 和 AES-256
bkey = "12345678901234561234567890123456"
print(bkey)
raw="test raw data 123 456 abcde";
raw = pad(raw)
iv ="0102030405060708";
print("iv="+iv)
cipher = AES.new(bkey, AES.MODE_CBC, iv )
print(len(raw))
print(raw)
ciphertext= cipher.encrypt(raw)
print(ciphertext)
ciphertext_base64=base64.b64encode(ciphertext)
print(ciphertext_base64)
print('============================')
enc=base64.b64decode(ciphertext_base64)
cipher = AES.new(bkey, AES.MODE_CBC, iv )
text=cipher.decrypt(enc);
print(len(text))
print(text)
print(text.hex())
plaintext= unpad(text)
print("%s" % plaintext.decode())
```
# RSA2048签名验签
使用依赖`pip3 install pycrypto`。
生成公私钥对:
```bash
openssl genrsa -out ./myPrivateKey.pem -passout pass:"f00bar" -des3 2048
openssl rsa -pubout -in ./myPrivateKey.pem -passin pass:"f00bar" -out ./myPublicKey.pem
```
测试代码:
```python
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA
from Crypto.Signature import PKCS1_v1_5
from base64 import b64encode, b64decode
def rsa_sign(message):
private_key_file = open('./myPrivateKey.pem', 'r')
private_key = RSA.importKey(private_key_file.read(), 'f00bar')
hash_obj = SHA.new(message)
signer = PKCS1_v1_5.new(private_key)
d = b64encode(signer.sign(hash_obj))
return d
def rsa_verify(message, signature):
public_key_file = open('./myPublicKey.pem', 'r')
public_key = RSA.importKey(public_key_file.read())
sign = b64decode(signature)
h = SHA.new(message)
verifier = PKCS1_v1_5.new(public_key)
return verifier.verify(h, sign)
msg = b'asdasdasdasdasdasd'
s = rsa_sign(msg)
print(s)
v = rsa_verify(msg, s)
print(v)
v = rsa_verify(msg + b'a', s)
print(v)
```
# pkcs8
```bash
openssl pkcs8 -topk8 -inform PEM -in ClientPrivateKey.pem -passin pass:"f00bar" -outform pem -nocrypt -out ClientPrivateKeypkcs8.pem
```
-
投票私链交付文档
https://feelncut.com/2018/03/06/104.html
2018-03-06T21:42:00+08:00
[TOC]
### 环境要求
开发环境:
Ubuntu 16.04
Python 3.5+
PM2
创世区块分配钱包地址为:`0x4a244BF6834f7569A726DB8ec0D3B24D31ce52c3`
私钥为:`0x4a115bf4ec4e27fce40db37c974d526953e50cc5c1edbffef3f724062fcb01c7`
### 环境安装
#### 安装PM2
PM2用于管理Geth和Web API后台进程。
**参考安装方式**:通过 nvm 安装 NodeJS
```
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.1/install.sh | bash
source ~/.bashrc
nvm install v6.9.1
npm install -g pm2
```
#### 安装Python环境
安装Web API 必须环境:
安装时注意python应使用python3,如果系统带有python2.7和python3.5,下面命令应使用`python3`。
```
# python 包管理器pip
sudo apt-get python3-pip
sudo pip install --upgrade pip
# python web framework
sudo pip install flask
# python web server
sudo pip install gunicorn
# install web3.py
sudo apt-get install libssl-dev libffi-dev autoconf automake libtool
git clone [email protected]:ethereum/web3.py.git
cd web3.py
pip install -r requirements-dev.txt
pip install -e .[tester]
# install pyethereum
sudo apt-get install libssl-dev build-essential automake pkg-config libtool libffi-dev libgmp-dev libyaml-cpp-dev
git clone https://github.com/ethereum/pyethereum/
cd pyethereum
python setup.py install
```
### 部署节点
#### 部署主节点
```
cd vote_master
# start block chain
pm2 start geth.sh
# start web api
pm2 start web.sh
# show pm2 list
pm2 list
# show nodeInfo
./geth attach http://127.0.0.1:8545
# 控制台内输入
admin.nodeInfo
```
保存nodeInfo中的enode:
```
"enode://7c2222797bc4579e5675d75a4ed6803606f7ea925ffd83ce58712e21488c5a30c107758ac69098e791f4589a23663cfb8484d0f56663e06f4d1b9517f3b685f0@[::]:30101"
```
注意:`[::]`替换为`ip`
更多pm2命令参考:http://pm2.keymetrics.io/docs/usage/quick-start/
#### 部署挖矿节点
```
cd vote_miner
# 初始化挖矿节点
bash init.sh
```
在`data`目录下新建`static-nodes.json`,保存一下内容,注意替换`ip`:
```
["enode://7c2222797bc4579e5675d75a4ed6803606f7ea925ffd83ce58712e21488c5a30c107758ac69098e791f4589a23663cfb8484d0f56663e06f4d1b9517f3b685f0@ip:30101"]
```
```
# 启动节点
pm2 start miner.sh
```
至此,环境部署完毕。
### 智能合约
`smart contracts`下`token contract`为代币智能合约源代码,`abu.js`和`votes.js`为合约部署文件。部署智能合约参考推荐在控制台中部署。
-
Geth控制台的进阶使用
https://feelncut.com/2018/03/05/103.html
2018-03-05T23:13:00+08:00
[TOC]
#### 两个参数
```
// js加载路径,默认当前目录
--jspath loadScript
// 要执行的js命令
--exec value
```
启动Geth时加上`--jspath script --exec "loadScript('help.js')"`
#### 查看所有钱包账户余额
上面两个参数加载help.js到控制台,我们可以在help.js中写一些辅助函数帮助我们提升效率。
```
function checkAllBalances() {
var i =0;
eth.accounts.forEach( function(e){
console.log(" eth.accounts["+i+"]: " + e + " \tbalance: " + web3.fromWei(eth.getBalance(e), "ether") + " ether");
i++;
})
};
```
注意: eth.accounts为当前控制台里新建的所有钱包,不是值整个区块链上的钱包地址。
#### 仅在有交易时挖矿
```
function minerWhenTransaction() {
function checkWork() {
if (eth.getBlock("pending").transactions.length > 0) {
if (eth.mining) return;
console.log("== Pending transactions! Mining...==");
miner.start(1);
} else {
miner.stop(); // This param means nothing
console.log("== No transactions! Mining stopped.==");
}
}
eth.filter("latest", function(err, block) { checkWork(); });
eth.filter("pending", function(err, block) { checkWork(); });
checkWork();
}
```
#### 查看代币余额
```
...
```
当然你还可以实现其他更多辅助功能。
-
以太坊搭建POW私链及注意事项
https://feelncut.com/2018/03/05/102.html
2018-03-05T23:01:00+08:00
[TOC]
主要参考:https://github.com/ethereum/go-ethereum/wiki/Private-network
### 初始化创世区块
json文件:
```
{
"config": {
"chainId": 15,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"difficulty": "200000000",
"gasLimit": "2100000",
"alloc": {
"7df9a875a174b3bc565e6424a0050ebc1b2d1d82": { "balance": "300000" },
"f41c74c9ae680c1aa78f42e5647a62f353b7bdde": { "balance": "400000" }
}
}
```
chainId最好和主网测试网区别开,difficulty是挖矿难度,可以改小一点,alloc是创世区块预先分配的ETH,确保你知道密钥,否则之后无法使用该钱包。
初始化命令:
```
geth --datadir=data init genesis.json
```
`-datadir`指定区块存储地址。
### 启动节点
命令:
```
geth --identity "myname" --rpc --rpccorsdomain "*" --datadir data/ --port "30303" --rpcapi "db,eth,net,web3,personal,admin,miner" --networkid 15 console
```
`networkid`最好和`chainId`一致,否则无法使用`MetaMask`。
`--rpc`表示开启json rpc服务,`--rpcapi`表示允许rpc使用哪些API
更多参数参见:https://github.com/ethereum/go-ethereum/wiki/Command-Line-Options
遇到关闭节点后,区块不保存的现象,加上:`--gcmode=archive`即可。
### 使用控制台
通过`console`命令进入控制台后,可能会用到一下命令:
```
// 创建账号:
personal.newAccount('123456')
// 查询账户:
eth.accounts
// 账户赋值给变量:
u1 =eth.accounts[0]
u2 =eth.accounts[1]
// 查询账户余额:
eth.getBalance(u1)
// 显示当前区块:
eth.blockNumber
// 开始挖矿(默认第一个账户得到挖矿收益):
miner.start()
// 手动指定挖矿收益账户
miner.setEtherbase('0x067D19026e1C15a1b641a191D188542A98f2060e');
// 设定gasPrice
miner.setGasPrice(0x123456);
// 停止挖矿:
miner.stop()
// 解锁账户(获得账户使用权):
personal.unlockAccount(user1, "123456")
// user1转账3以太币给user2:
eth.sendTransaction({from: u1, to: u2, value: web3.toWei(1,"ether")})
// 查看交易
eth.getTransaction(txhash)
// 查看交易凭证
eth.getTransactionReceipt(txhash)
// 查看txpool
txpool
// 查看nodeInfo
admin.nodeInfo
// 查看已连接节点
admin.peers
```
更多命令参见:https://github.com/ethereum/go-ethereum/wiki/Management-APIs
注意,u1发送转账后必须经过挖矿u2才可以收到ETH。
### 连接节点
A节点通过`admin.nodeInfo`查看节点信息。其中包含了:
```
enode: "enode://44826a5d6a55f88a18298bca4773fca5749cdc3a5c9f308aa7d810e9b31123f3e7c5fba0b1d70aac5308426f47df2a128a6747040a3815cc7dd7167d03be320d@[::]:30303"
```
B节点连接A节点有两种方式:
1.B节点datadir目录下新建`static-nodes.json`,内容:
```
["enode://44826a5d6a55f88a18298bca4773fca5749cdc3a5c9f308aa7d810e9b31123f3e7c5fba0b1d70aac5308426f47df2a128a6747040a3815cc7dd7167d03be320d@ip:30303"]
```
2.B节点控制台下:
```
admin.addPeer("enode://44826a5d6a55f88a18298bca4773fca5749cdc3a5c9f308aa7d810e9b31123f3e7c5fba0b1d70aac5308426f47df2a128a6747040a3815cc7dd7167d03be320d@ip:30303")
```
注意:如果向A节点提交了交易,B节点txpool未收到交易,只需要在A节点开启一下矿工,待B收到txpool之后关闭A节点矿工即可。
-
以太坊Geth的四种安装方法
https://feelncut.com/2018/03/05/101.html
2018-03-05T18:29:06+08:00
[TOC]
详细可参考:https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum
安装最简单方便的方法为`二进制安装`,其次`PPA安装`。
### 二进制安装
官方提供了编译好的二进制安装包,直接下载即可使用。Linux下可以将`Geth`所在目录添加到环境变量,或者直接`sudo mv Geth /usr/bin`。
下载地址:https://geth.ethereum.org/downloads/
### Ubuntu下通过PPA安装
```
sudo apt-get install software-properties-common
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install ethereum
```
### 源代码安装
通过golang编译源代码:
```
sudo apt-get install -y build-essential golang
cd go-ethereum
make geth
```
编译完成后在目录`build/bin/geth`下可以看到编译好的Geth。
### 通过docker安装
Geth不像Hyperledger安装这么麻烦,不建议docker安装,如有需要,参考:https://github.com/ethereum/go-ethereum/wiki/Running-in-Docker