open-ethereum-pool以太坊礦池原始碼分析(5)proxy模組
# open-ethereum-pool以太坊礦池-proxy模組
## ProxyServer定義
```go
type ProxyServer struct {
config *Config
blockTemplate atomic.Value
upstream int32
upstreams []*rpc.RPCClient
backend *storage.RedisClient
diff string
policy *policy.PolicyServer
hashrateExpiration time.Duration
failsCount int64
// Stratum
sessionsMu sync.RWMutex
sessions map[*Session]struct{}
timeout time.Duration
}
```
## BlockTemplate定義
```go
type BlockTemplate struct {
sync.RWMutex
Header string
Seed string
Target string
Difficulty *big.Int
Height uint64
GetPendingBlockCache *rpc.GetBlockReplyPart
nonces map[string]bool
headers map[string]heightDiffPair
}
type heightDiffPair struct {
diff *big.Int
height uint64
}
```
## 以太坊Pow演算法原理
```
//以太坊Pow演算法可以表示為如下公式:
//RAND(h, n) <= M / d
//其中RAND()表示一個概念函式,代表一系列的複雜運算。 其中h和n為輸入,即區塊Header的雜湊、以及Header中的Nonce。
//M表示一個極大的數,此處使用2^256-1。 d,為區塊難度,即Header中的Difficulty。
//因此在h和n確定的情況下,d越大,挖礦難度越大,即為Difficulty本義。 即不斷變更Nonce,使RAND(h, n)滿足RAND(h, n) <= M / d,即完成Pow。
```
## NewProxy流程圖
## ProxyServer Start流程圖
## eth_submitWork處理流程圖
即:processShare()
## WriteNodeState原理
```go
//cfg.Proxy.StateUpdateInterval為WriteNodeState定時器,時間為3s
//調取:err := backend.WriteNodeState(cfg.Name, t.Height, t.Difficulty)
func (r *RedisClient) WriteNodeState(id string, height uint64, diff *big.Int) error {
tx := r.client.Multi()
defer tx.Close()
now := util.MakeTimestamp() / 1000
_, err := tx.Exec(func() error {
//HSET eth:nodes:main:name main
tx.HSet(r.formatKey("nodes"), join(id, "name"), id)
//HSET eth:nodes:main:height height
tx.HSet(r.formatKey("nodes"), join(id, "height"), strconv.FormatUint(height, 10))
//HSET eth:nodes:main:difficulty difficulty
tx.HSet(r.formatKey("nodes"), join(id, "difficulty"), diff.String())
//HSET eth:nodes:main:lastBeat now
tx.HSet(r.formatKey("nodes"), join(id, "lastBeat"), strconv.FormatInt(now, 10))
return nil
})
return err
}
```
## WriteBlock原理
```go
//調取:exist, err := s.backend.WriteBlock(login, id, params, shareDiff, h.diff.Int64(), h.height, s.hashrateExpiration)
//s.hashrateExpiration即cfg.Proxy.HashrateExpiration,為3h,即TTL(生命週期) for workers stats,通常等於hashrateLargeWindow
func (r *RedisClient) WriteBlock(login, id string, params []string, diff, roundDiff int64, height uint64, window time.Duration) (bool, error) {
//寫入eth:pow中,並檢查是否已存在
exist, err := r.checkPoWExist(height, params)
if err != nil {
return false, err
}
// Duplicate share, (nonce, powHash, mixDigest) pair exist
//已存在
if exist {
return true, nil
}
tx := r.client.Multi()
defer tx.Close()
ms := util.MakeTimestamp()
ts := ms / 1000 //轉換成秒
cmds, err := tx.Exec(func() error {
//調取writeShare
r.writeShare(tx, ms, ts, login, id, diff, window)
//HSET eth:stats lastBlockFound ts
//Hset 命令用於為雜湊表中的欄位賦值
tx.HSet(r.formatKey("stats"), "lastBlockFound", strconv.FormatInt(ts, 10))
//HDEL eth:stats roundShares
//Hdel 命令用於刪除雜湊表 key 中的一個或多個指定欄位,不存在的欄位將被忽略
tx.HDel(r.formatKey("stats"), "roundShares")
//ZINCRBY eth:finders 1 login
//Zincrby 命令對有序集合中指定成員的分數加上增量 increment
tx.ZIncrBy(r.formatKey("finders"), 1, login)
//HINCRBY eth:miners:login blocksFound 1
//Hincrby 命令用於為雜湊表中的欄位值加上指定增量值
tx.HIncrBy(r.formatKey("miners", login), "blocksFound", 1)
//RENAME eth:shares:roundCurrent eth:shares:round&height:nonce
//Rename 命令用於修改 key 的名稱
tx.Rename(r.formatKey("shares", "roundCurrent"), r.formatRound(int64(height), params[0]))
//HGETALL eth:shares:round&height:nonce
//Hgetall 命令用於返回雜湊表中,所有的欄位和值
tx.HGetAllMap(r.formatRound(int64(height), params[0]))
return nil
})
if err != nil {
return false, err
} else {
//HGETALL eth:shares:round&height:nonce
//Hgetall 命令用於返回雜湊表中,所有的欄位和值
sharesMap, _ := cmds[10].(*redis.StringStringMapCmd).Result()
totalShares := int64(0)
for _, v := range sharesMap {
n, _ := strconv.ParseInt(v, 10, 64)
totalShares += n
}
//nonce、powHash、mixDigest
hashHex := strings.Join(params, ":")
//MakeTimestamp、h.diff、totalShares
s := join(hashHex, ts, roundDiff, totalShares)
//ZADD eth:blocks:candidates height nonce:powHash:mixDigest:MakeTimestamp:h.diff:totalShares
//Zadd 命令用於將一個或多個成員元素及其分數值加入到有序集當中
//candidates為候選者
cmd := r.client.ZAdd(r.formatKey("blocks", "candidates"), redis.Z{Score: float64(height), Member: s})
return false, cmd.Err()
}
}
func (r *RedisClient) checkPoWExist(height uint64, params []string) (bool, error) {
// Sweep PoW backlog for previous blocks, we have 3 templates back in RAM
//掃描積壓的前塊
//ZREMRANGEBYSCORE eth:pow -inf (height-8
//Zremrangebyscore 命令用於移除有序集中,指定分數(score)區間內的所有成員
r.client.ZRemRangeByScore(r.formatKey("pow"), "-inf", fmt.Sprint("(", height-8))
//ZADD eth:pow height params
//Zadd 命令用於將一個或多個成員元素及其分數值加入到有序集當中
val, err := r.client.ZAdd(r.formatKey("pow"), redis.Z{Score: float64(height), Member: strings.Join(params, ":")}).Result()
return val == 0, err
}
```
## WriteShare原理
```go
func (r *RedisClient) WriteShare(login, id string, params []string, diff int64, height uint64, window time.Duration) (bool, error) {
//ZADD eth:pow height params
//寫入eth:pow中,並檢查是否已存在
exist, err := r.checkPoWExist(height, params)
if err != nil {
return false, err
}
// Duplicate share, (nonce, powHash, mixDigest) pair exist
//已存在
if exist {
return true, nil
}
tx := r.client.Multi()
defer tx.Close()
ms := util.MakeTimestamp()
ts := ms / 1000
_, err = tx.Exec(func() error {
r.writeShare(tx, ms, ts, login, id, diff, window)
//HINCRBY eth:stats roundShares diff
//Hincrby 命令用於為雜湊表中的欄位值加上指定增量值
tx.HIncrBy(r.formatKey("stats"), "roundShares", diff)
return nil
})
return false, err
}
func (r *RedisClient) writeShare(tx *redis.Multi, ms, ts int64, login, id string, diff int64, expire time.Duration) {
//HINCRBY eth:shares:roundCurrent login diff
//Hincrby 命令用於為雜湊表中的欄位值加上指定增量值
tx.HIncrBy(r.formatKey("shares", "roundCurrent"), login, diff)
//ZADD eth:hashrate ts diff:login:id:ms
//Zadd 命令用於將一個或多個成員元素及其分數值加入到有序集當中
tx.ZAdd(r.formatKey("hashrate"), redis.Z{Score: float64(ts), Member: join(diff, login, id, ms)})
//ZADD eth:hashrate:login ts diff:login:id:ms
tx.ZAdd(r.formatKey("hashrate", login), redis.Z{Score: float64(ts), Member: join(diff, id, ms)})
//EXPIRE eth:hashrate:login expire
//expire即cfg.Proxy.HashrateExpiration,即3小時
tx.Expire(r.formatKey("hashrate", login), expire) // Will delete hashrates for miners that gone
//HSET eth:miners:login lastShare ts
//Hset 命令用於為雜湊表中的欄位賦值
tx.HSet(r.formatKey("miners", login), "lastShare", strconv.FormatInt(ts, 10))
}
```
## Stratum Mining Protocol
### eth_submitLogin
```json
//Request
{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_submitLogin",
"params": ["0xb85150eb365e7df0941f0cf08235f987ba91506a"]
}
//或
{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_submitLogin",
"params": ["0xb85150eb365e7df0941f0cf08235f987ba91506a", "admin@example.net"]
}
//Successful response
{ "id": 1, "jsonrpc": "2.0", "result": true }
//{ "id": 1, "jsonrpc": "2.0", "result": null, "error": { code: -1, message: "Invalid login" } }
```
### eth_getWork
```json
//Request
{ "id": 1, "jsonrpc": "2.0", "method": "eth_getWork" }
//Successful response
{
"id": 1,
"jsonrpc": "2.0",
"result": [
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"0x5eed00000000000000000000000000005eed0000000000000000000000000000",
"0xd1ff1c01710000000000000000000000d1ff1c01710000000000000000000000"
]
}
//Exceptions
{ "id": 10, "result": null, "error": { code: 0, message: "Work not ready" } }
```
### New Job Notification
```json
//New Job Notification
{
"jsonrpc": "2.0",
"result": [
"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"0x5eed00000000000000000000000000005eed0000000000000000000000000000",
"0xd1ff1c01710000000000000000000000d1ff1c01710000000000000000000000"
]
}
```
### eth_submitWork
```json
//Request
{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_submitWork",
"params": [
"0xe05d1fd4002d962f",
"0x6c872e2304cd1e64b553a65387d7383470f22331aff288cbce5748dc430f016a",
"0x2b20a6c641ed155b893ee750ef90ec3be5d24736d16838b84759385b6724220d"
]
}
//Response
{ "id": 1, "jsonrpc": "2.0", "result": true }
{ "id": 1, "jsonrpc": "2.0", "result": false }
//Exceptions
{ "id": 1, "jsonrpc": "2.0", "result": null, "error": { code: 23, message: "Invalid share" } }
{ "id": 1, "jsonrpc": "2.0", "result": null, "error": { code: 22, message: "Duplicate share" } }
{ "id": 1, "jsonrpc": "2.0", "result": null, "error": { code: -1, message: "High rate of invalid shares" } }
{ "id": 1, "jsonrpc": "2.0", "result": null, "error": { code: 25, message: "Not subscribed" } }
{ "id": 1, "jsonrpc": "2.0", "result": null, "error": { code: -1, message: "Malformed PoW result" } }
```
### Submit Hashrate
```json
{ "id": 1, "jsonrpc": "2.0", "result": true }
```
## Geth JavaScript console
```shell
//getBlock
> eth.getBlock('pending')
{
author: "0xdda50d9783dfda1c7ac51c4920f3561e17438be7",
difficulty: 550853386,
extraData: "0xd5830109048650617269747986312e32342e30826c69",
gasLimit: 4700036,
gasUsed: 3933311,
hash: "0x6615dc650abc224822e3328155f843a5b441d2de11e7bb6dfc8bdecfc22ad3f8",
logsBloom: "0x02000000000000010000000000000000400000000000800000000000000000000000000000000400000000800000000000000000000000400000000000000000000000001000000000020008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000080000040000004000000004000080000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000001000040000000000000000000000000000000000000010000000000000000000000000000000000000000000000000100000",
miner: "0xdda50d9783dfda1c7ac51c4920f3561e17438be7",
number: 2753366,
parentHash: "0x31256e245ce314c0b5cf4007d21b7baebb46e2beb3e6b445809d8bceb1bd3039",
receiptsRoot: "0x9d89da07e7300f4edc5ef580a6ccbaaffae76a978f9ee4d77fb83a7907a8c508",
sealFields: [],
sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
size: 2455,
stateRoot: "0x557340ac77aef679dae4ddef6a426436659a4e1e9588c85fb5da74491d28fe8b",
timestamp: 1519976198,
totalDifficulty: 7852523064449795,
transactions: ["0x715eb518875555fd6abf3cb8e90588222d3be89554a64e2dac72ba58ed729d78", "0xcfbf33be2bd2141cc9d5a5896d2fb99c978a8d75bce59462b645733ff57bcfd0", "0x82eb59d32abb36d2754a48e2e581ec8c9809f9180f7200ea334bcb746365797a", "0xe0d0f519452d4aad44c706aee65e99dce6e3c15876a71daa32e1496e803cf8e5", "0x3731d60c5dd0c1013555312bef2471de0c30978d9ab611f28325addd44492664", "0x0fb9b1fee161632c069068bec45b910dc2cd013480dea5987e1da84e8f779cd7", "0xc5dade656fa25bb044398675851765a8f8182112d7a400e8a0c4e6f4045bd42b", "0xfe41aa0ee9090d623609435b0b8b8e5ab3b6019d79560396956a5f4a5f3c1357", "0xe40c8e78ec16ea4bc1c445749dfaddb6777d6652e9882a5ab8ae48b316cc926e", "0xc08fac21754c516ba3e61c9a6b0a51982c7b680e48c80c04e9572c6e1b2adbb4", "0x2a5d22570373f21f6989b2228d7031d42bdbac13992152e55a95af441e20138a", "0x204b56dd370fe9f73282df925168f6375b5cccb38a681e9cb97855aed2e34aee", "0x5be5b6ea903e66ced2de9674e48639032aad4eca3f970605a3fbb0162e481da3", "0xc35a3b3fab6ae3503287a765497c82f4687f536676c79c87771d1332d0d0d313"],
transactionsRoot: "0x07bf02d4b8239576682c33d9393998401112dd011b57ac77042fe1981830c3e1",
uncles: []
}
//getWork
> eth.getWork()
["0x6615dc650abc224822e3328155f843a5b441d2de11e7bb6dfc8bdecfc22ad3f8", "0xcadf16f9c673bb7540bc190a9eed2b04fd59a98a7d4f631d85c240ad6155bfa9", "0x00000007cc03d7d0cb49aa514f6aed05705a9baef46aea9a02514c253e288daa"]
```
## 參考文件
* [eth_getblockbynumber](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getblockbynumber)
* [以太幣的挖礦機制](http://ethfans.org/topics/18)
* [以太坊ETH挖礦詳細教程](https://www.cybtc.com/thread-15905-1-1.html)
* [JavaScript Runtime Environment](https://ethereum.gitbooks.io/frontier-guide/content/jsre.html)
* [Management APIs](https://github.com/ethereum/go-ethereum/wiki/Management-APIs)
* [Pacy-以太坊礦池流程圖](https://processon.com/u/58748c7ee4b09f680a4af83e)
* [Stratum Mining Protocol](https://github.com/sammy007/open-ethereum-pool/blob/master/docs/STRATUM.md)
* [JSON-RPC methods](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getwork)
* [cpp-ethereum/libethash](https://github.com/ethereum/cpp-ethereum/tree/develop/libethash)
* [Web3.js API 中文文件](http://web3.tryblockchain.org/Web3.js-api-refrence.html)
* [Redis Command 命令](http://www.runoob.com/redis/server-command.html)
網址:http://www.qukuailianxueyuan.io/
欲領取造幣技術與全套虛擬機器資料
區塊鏈技術交流QQ群:756146052 備註:CSDN
尹成學院微信:備註:CSDN
網址:http://www.qukuailianxueyuan.io/
欲領取造幣技術與全套虛擬機器資料
區塊鏈技術交流QQ群:756146052 備註:CSDN
尹成學院微信:備註:CSDN
相關文章
- open-ethereum-pool以太坊礦池原始碼分析(3)payouts模組原始碼
- open-ethereum-pool以太坊礦池原始碼分析(4)-policy模組原始碼
- open-ethereum-pool以太坊礦池原始碼分析(6)-redis模組原始碼Redis
- open-ethereum-pool以太坊礦池原始碼分析(7)unlocker模組原始碼
- open-ethereum-pool以太坊礦池原始碼分析(2)API分析原始碼API
- open-ethereum-pool以太坊礦池原始碼分析(1)-main入口分析原始碼AI
- open-ethereum-pool以太坊礦池原始碼分析(1)環境安裝原始碼
- btcpool礦池原始碼分析(5)-JobMaker模組解析TCP原始碼
- 以太坊交易池原始碼分析原始碼
- 以太坊原始碼分析(16)挖礦分析原始碼
- 以太坊原始碼分析(42)miner挖礦部分原始碼分析CPU挖礦原始碼
- 以太坊原始碼分析(5)accounts程式碼分析原始碼
- 以太坊原始碼分析(26)core-txpool交易池原始碼分析原始碼
- btcpool礦池原始碼分析(3)-BlockMaker模組解析TCP原始碼BloC
- btcpool礦池原始碼分析(4)-GbtMaker模組解析TCP原始碼
- btcpool礦池原始碼分析(6)-nmcauxmaker模組解析TCP原始碼UX
- btcpool礦池原始碼分析(6)-PoolWatcher模組解析TCP原始碼
- btcpool礦池原始碼分析(7)-sharelogger模組解析TCP原始碼
- btcpool礦池原始碼分析(9)-statshttpd模組解析TCP原始碼httpd
- btcpool礦池原始碼分析(10)-StratumServer模組解析TCP原始碼Server
- 死磕以太坊原始碼分析之挖礦流程分析原始碼
- 以太坊交易池原始碼解析原始碼
- 以太坊原始碼分析(37)eth以太坊協議分析原始碼協議
- 以太坊原始碼分析(18)以太坊交易執行分析原始碼
- 以太坊原始碼分析(36)ethdb原始碼分析原始碼
- 以太坊原始碼分析(38)event原始碼分析原始碼
- 以太坊原始碼分析(41)hashimoto原始碼分析原始碼
- 以太坊原始碼分析(43)node原始碼分析原始碼
- 以太坊原始碼分析(51)rpc原始碼分析原始碼RPC
- 以太坊原始碼分析(52)trie原始碼分析原始碼
- 以太坊原始碼分析(13)RPC分析原始碼RPC
- 以太坊原始碼分析(52)以太坊fast sync演算法原始碼AST演算法
- 以太坊原始碼分析(1)go-ethereum的設計思路及模組組織形式原始碼Go
- 以太坊原始碼分析(8)區塊分析原始碼
- 以太坊原始碼分析(9)cmd包分析原始碼
- 以太坊原始碼分析(35)eth-fetcher原始碼分析原始碼
- 以太坊原始碼分析(20)core-bloombits原始碼分析原始碼OOM
- 以太坊原始碼分析(24)core-state原始碼分析原始碼