Skip to content

Commit

Permalink
PPLNS support
Browse files Browse the repository at this point in the history
 * Secure Last N Shares
 * Fix N Shares

PPLNS cleanup by Ellaismer <[email protected]>
 * Fix roundshare API display error
 * Move roundshare stats to minerstates

squash and minor cleanup by hackyminer <[email protected]> 2018-10-26
  • Loading branch information
boehla authored and hackmod committed Oct 30, 2018
1 parent bcfc0eb commit b6e5c33
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 12 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* Modern beautiful Ember.js frontend
* Separate stats for workers: can highlight timed-out workers so miners can perform maintenance of rigs
* JSON-API for stats
* PPLNS block reward

#### Proxies

Expand Down
1 change: 1 addition & 0 deletions config.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"threads": 2,
"coin": "eth",
"name": "main",
"pplns": 9000,

"proxy": {
"enabled": true,
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func main() {

startNewrelic()

backend = storage.NewRedisClient(&cfg.Redis, cfg.Coin)
backend = storage.NewRedisClient(&cfg.Redis, cfg.Coin, cfg.Pplns)
pong, err := backend.Check()
if err != nil {
log.Printf("Can't establish connection to backend: %v", err)
Expand Down
7 changes: 6 additions & 1 deletion payouts/unlocker.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,12 @@ func (u *BlockUnlocker) calculateRewards(block *storage.BlockData) (*big.Rat, *b
return nil, nil, nil, nil, err
}

rewards := calculateRewardsForShares(shares, block.TotalShares, minersProfit)
totalShares := int64(0)
for _, val := range shares {
totalShares += val
}

rewards := calculateRewardsForShares(shares, totalShares, minersProfit)

if block.ExtraReward != nil {
extraReward := new(big.Rat).SetInt(block.ExtraReward)
Expand Down
1 change: 1 addition & 0 deletions proxy/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type Config struct {
Threads int `json:"threads"`

Coin string `json:"coin"`
Pplns int64 `json:"pplns"`
Redis storage.Config `json:"redis"`

BlockUnlocker payouts.UnlockerConfig `json:"unlocker"`
Expand Down
58 changes: 50 additions & 8 deletions storage/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type Config struct {
type RedisClient struct {
client *redis.Client
prefix string
pplns int64
}

type BlockData struct {
Expand Down Expand Up @@ -78,14 +79,14 @@ type Worker struct {
TotalHR int64 `json:"hr2"`
}

func NewRedisClient(cfg *Config, prefix string) *RedisClient {
func NewRedisClient(cfg *Config, prefix string, pplns int64) *RedisClient {
client := redis.NewClient(&redis.Options{
Addr: cfg.Endpoint,
Password: cfg.Password,
DB: cfg.Database,
PoolSize: cfg.PoolSize,
})
return &RedisClient{client: client, prefix: prefix}
return &RedisClient{client: client, prefix: prefix, pplns: pplns}
}

func (r *RedisClient) Client() *redis.Client {
Expand Down Expand Up @@ -210,14 +211,36 @@ func (r *RedisClient) WriteBlock(login, id string, params []string, diff, roundD
tx.HDel(r.formatKey("stats"), "roundShares")
tx.ZIncrBy(r.formatKey("finders"), 1, login)
tx.HIncrBy(r.formatKey("miners", login), "blocksFound", 1)
tx.Rename(r.formatKey("shares", "roundCurrent"), r.formatRound(int64(height), params[0]))
tx.HGetAllMap(r.formatRound(int64(height), params[0]))
tx.HGetAllMap(r.formatKey("shares", "roundCurrent"))
tx.Del(r.formatKey("shares", "roundCurrent"))
tx.LRange(r.formatKey("lastshares"), 0, r.pplns)
return nil
})
if err != nil {
return false, err
} else {
sharesMap, _ := cmds[10].(*redis.StringStringMapCmd).Result()

shares := cmds[len(cmds)-1].(*redis.StringSliceCmd).Val()

tx2 := r.client.Multi()
defer tx2.Close()

totalshares := make(map[string]int64)
for _, val := range shares {
totalshares[val] += 1
}

_, err := tx2.Exec(func() error {
for k, v := range totalshares {
tx2.HIncrBy(r.formatRound(int64(height), params[0]), k, v)
}
return nil
})
if err != nil {
return false, err
}

sharesMap, _ := cmds[len(cmds)-3].(*redis.StringStringMapCmd).Result()
totalShares := int64(0)
for _, v := range sharesMap {
n, _ := strconv.ParseInt(v, 10, 64)
Expand All @@ -231,6 +254,9 @@ func (r *RedisClient) WriteBlock(login, id string, params []string, diff, roundD
}

func (r *RedisClient) writeShare(tx *redis.Multi, ms, ts int64, login, id string, diff int64, expire time.Duration) {
tx.LPush(r.formatKey("lastshares"), login)
tx.LTrim(r.formatKey("lastshares"), 0, r.pplns)

tx.HIncrBy(r.formatKey("shares", "roundCurrent"), login, diff)
tx.ZAdd(r.formatKey("hashrate"), redis.Z{Score: float64(ts), Member: join(diff, login, id, ms)})
tx.ZAdd(r.formatKey("hashrate", login), redis.Z{Score: float64(ts), Member: join(diff, id, ms)})
Expand Down Expand Up @@ -271,6 +297,13 @@ func join(args ...interface{}) string {
} else {
s[i] = "0"
}
case *big.Rat:
x := v.(*big.Rat)
if x != nil {
s[i] = x.FloatString(9)
} else {
s[i] = "0"
}
default:
panic("Invalid type specified for conversion")
}
Expand Down Expand Up @@ -577,7 +610,8 @@ func (r *RedisClient) GetMinerStats(login string, maxPayments int64) (map[string
tx.HGetAllMap(r.formatKey("miners", login))
tx.ZRevRangeWithScores(r.formatKey("payments", login), 0, maxPayments-1)
tx.ZCard(r.formatKey("payments", login))
tx.HGet(r.formatKey("shares", "roundCurrent"), login)
tx.HGet(r.formatKey("shares", "currentShares"), login)
tx.LRange(r.formatKey("lastshares"), 0, r.pplns)
return nil
})

Expand All @@ -589,8 +623,14 @@ func (r *RedisClient) GetMinerStats(login string, maxPayments int64) (map[string
payments := convertPaymentsResults(cmds[1].(*redis.ZSliceCmd))
stats["payments"] = payments
stats["paymentsTotal"] = cmds[2].(*redis.IntCmd).Val()
roundShares, _ := cmds[3].(*redis.StringCmd).Int64()
stats["roundShares"] = roundShares
shares := cmds[4].(*redis.StringSliceCmd).Val()
csh := 0
for _, val := range shares {
if val == login {
csh++
}
}
stats["roundShares"] = csh
}

return stats, nil
Expand Down Expand Up @@ -668,6 +708,7 @@ func (r *RedisClient) CollectStats(smallWindow time.Duration, maxBlocks, maxPaym
tx.ZCard(r.formatKey("blocks", "matured"))
tx.ZCard(r.formatKey("payments", "all"))
tx.ZRevRangeWithScores(r.formatKey("payments", "all"), 0, maxPayments-1)
tx.LLen(r.formatKey("lastshares"))
return nil
})

Expand All @@ -676,6 +717,7 @@ func (r *RedisClient) CollectStats(smallWindow time.Duration, maxBlocks, maxPaym
}

result, _ := cmds[2].(*redis.StringStringMapCmd).Result()
result["nShares"] = strconv.FormatInt(cmds[11].(*redis.IntCmd).Val(), 10)
stats["stats"] = convertStringMap(result)
candidates := convertCandidateResults(cmds[3].(*redis.ZSliceCmd))
stats["candidates"] = candidates
Expand Down
2 changes: 1 addition & 1 deletion storage/redis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var r *RedisClient
const prefix = "test"

func TestMain(m *testing.M) {
r = NewRedisClient(&Config{Endpoint: "127.0.0.1:6379"}, prefix)
r = NewRedisClient(&Config{Endpoint: "127.0.0.1:6379"}, prefix, 3000)
reset()
c := m.Run()
reset()
Expand Down
2 changes: 1 addition & 1 deletion www/app/controllers/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default Ember.Controller.extend({

roundPercent: Ember.computed('stats', 'model', {
get() {
var percent = this.get('model.roundShares') / this.get('stats.roundShares');
var percent = this.get('model.roundShares') / this.get('stats.nShares');
if (!percent) {
return 0;
}
Expand Down

0 comments on commit b6e5c33

Please sign in to comment.