diff --git a/gui/cache.go b/gui/cache.go index 47b728d6..595f0af4 100644 --- a/gui/cache.go +++ b/gui/cache.go @@ -236,13 +236,12 @@ func (c *Cache) updateHashData(hashData map[string][]*pool.HashData) { poolHashRate := new(big.Rat).SetInt64(0) for _, data := range hashData { for _, entry := range data { - hash, _ := new(big.Rat).SetString(entry.HashRate) - poolHashRate = poolHashRate.Add(poolHashRate, hash) + poolHashRate = poolHashRate.Add(poolHashRate, entry.HashRate) clientInfo[entry.AccountID] = append(clientInfo[entry.AccountID], &client{ Miner: entry.Miner, IP: entry.IP, - HashRate: hashString(hash), + HashRate: hashString(entry.HashRate), }) } } diff --git a/pool/boltdb.go b/pool/boltdb.go index bcdc6b1f..5f6e8074 100644 --- a/pool/boltdb.go +++ b/pool/boltdb.go @@ -1373,7 +1373,7 @@ func (db *BoltDB) persistHashData(hashData *HashData) error { }) } -// updateHashData persists the updated payment to the database. +// updateHashData persists the updated hash data to the database. func (db *BoltDB) updateHashData(hashData *HashData) error { const funcName = "updateHashData" return db.DB.Update(func(tx *bolt.Tx) error { @@ -1382,7 +1382,7 @@ func (db *BoltDB) updateHashData(hashData *HashData) error { return err } - // Assert the work provided exists before updating. + // Assert the hash data provided exists before updating. id := []byte(hashData.UUID) v := bkt.Get(id) if v == nil { @@ -1437,48 +1437,7 @@ func (db *BoltDB) fetchHashData(id string) (*HashData, error) { return &data, err } -// fetchAccountHashData fetches all hash data associated with the provided -// account id. -func (db *BoltDB) fetchAccountHashData(id string, minNano int64) ([]*HashData, error) { - const funcName = "fetchAccountHashData" - idB := []byte(id) - data := []*HashData{} - - err := db.DB.View(func(tx *bolt.Tx) error { - bkt, err := fetchBucket(tx, hashDataBkt) - if err != nil { - return err - } - - cursor := bkt.Cursor() - for k, v := cursor.First(); k != nil; k, v = cursor.Next() { - accID := k[8:] - if !bytes.Equal(idB, accID) { - continue - } - - var hashData HashData - err = json.Unmarshal(v, &hashData) - if err != nil { - desc := fmt.Sprintf("%s: unable to unmarshal hash data: %v", - funcName, err) - return errs.DBError(errs.Parse, desc) - } - - if hashData.UpdatedOn > minNano { - data = append(data, &hashData) - } - } - return nil - }) - if err != nil { - return nil, err - } - return data, err -} - -// listHashData fetches all hash data updated before the provided minimum time -// provided. +// listHashData fetches all hash data updated after the provided minimum time. func (db *BoltDB) listHashData(minNano int64) (map[string][]*HashData, error) { const funcName = "listHashData" data := make(map[string][]*HashData) @@ -1513,8 +1472,8 @@ func (db *BoltDB) listHashData(minNano int64) (map[string][]*HashData, error) { return data, err } -// pruneHashData prunes all hash data that have not been since the provided -// minimum time. +// pruneHashData prunes all hash data that have not been updated since +// the provided minimum time. func (db *BoltDB) pruneHashData(minNano int64) error { funcName := "pruneHashData" diff --git a/pool/boltupgrades.go b/pool/boltupgrades.go index 6751a2aa..d56a1371 100644 --- a/pool/boltupgrades.go +++ b/pool/boltupgrades.go @@ -404,7 +404,7 @@ func removeTxFeeReserveUpgrade(tx *bolt.Tx) error { } if dbVersion != oldVersion { - desc := fmt.Sprintf("%s: inappropriately called", err) + desc := fmt.Sprintf("%s: inappropriately called", funcName) return errs.DBError(errs.DBUpgrade, desc) } @@ -437,7 +437,7 @@ func shareCreatedOnUpgrade(tx *bolt.Tx) error { } if dbVersion != oldVersion { - desc := fmt.Sprintf("%s: inappropriately called", err) + desc := fmt.Sprintf("%s: inappropriately called", funcName) return errs.DBError(errs.DBUpgrade, desc) } @@ -506,7 +506,7 @@ func paymentUUIDUpgrade(tx *bolt.Tx) error { } if dbVersion != oldVersion { - desc := fmt.Sprintf("%s: inappropriately called", err) + desc := fmt.Sprintf("%s: inappropriately called", funcName) return errs.DBError(errs.DBUpgrade, desc) } @@ -601,7 +601,7 @@ func hashDataUpgrade(tx *bolt.Tx) error { } if dbVersion != oldVersion { - desc := fmt.Sprintf("%s: inappropriately called", err) + desc := fmt.Sprintf("%s: inappropriately called", funcName) return errs.DBError(errs.DBUpgrade, desc) } diff --git a/pool/chainstate.go b/pool/chainstate.go index 8135da63..0fe76546 100644 --- a/pool/chainstate.go +++ b/pool/chainstate.go @@ -223,6 +223,9 @@ func (cs *ChainState) handleChainUpdates(ctx context.Context) { } // Prune all hash data not updated in the past minute. + // A connected client should have updated multiple times + // in a minute. Only disconnected miners would not have + // updated within the timeframe. nowNano := time.Now().Add(-time.Minute).UnixNano() err = cs.cfg.db.pruneHashData(nowNano) if err != nil { diff --git a/pool/client.go b/pool/client.go index c102a7f0..cb76909d 100644 --- a/pool/client.go +++ b/pool/client.go @@ -1137,7 +1137,7 @@ func (c *Client) hashMonitor() { continue } - hashData.HashRate = hash.RatString() + hashData.HashRate = hash hashData.UpdatedOn = time.Now().UnixNano() err = c.cfg.db.updateHashData(hashData) diff --git a/pool/hashdata.go b/pool/hashdata.go index e5a1d5d3..565ffff8 100644 --- a/pool/hashdata.go +++ b/pool/hashdata.go @@ -13,12 +13,12 @@ import ( // HashData represents client identification and hashrate information // for a mining client. type HashData struct { - UUID string `json:"uuid"` - AccountID string `json:"accountid"` - Miner string `json:"miner"` - IP string `json:"ip"` - HashRate string `json:"hashrate"` - UpdatedOn int64 `json:"updatedon"` + UUID string `json:"uuid"` + AccountID string `json:"accountid"` + Miner string `json:"miner"` + IP string `json:"ip"` + HashRate *big.Rat `json:"hashrate"` + UpdatedOn int64 `json:"updatedon"` } // hashDataID generates a unique hash data id. @@ -35,7 +35,7 @@ func newHashData(miner string, accountID string, ip string, extraNonce1 string, return &HashData{ UUID: hashDataID(accountID, extraNonce1), AccountID: accountID, - HashRate: hashRate.RatString(), + HashRate: hashRate, IP: ip, Miner: miner, UpdatedOn: nowNano, diff --git a/pool/hashdata_test.go b/pool/hashdata_test.go index 7b83a299..c95b972e 100644 --- a/pool/hashdata_test.go +++ b/pool/hashdata_test.go @@ -25,7 +25,7 @@ func testHashData(t *testing.T) { } // Ensure hash data can be fetched. - hashID := hashDataID(xID, extraNonce1) + hashID := hashData.UUID fetchedHashData, err := db.fetchHashData(hashID) if err != nil { t.Fatal(err) @@ -37,7 +37,7 @@ func testHashData(t *testing.T) { hashData.UpdatedOn, fetchedHashData.UpdatedOn) } - if fetchedHashData.HashRate != hashData.HashRate { + if fetchedHashData.HashRate.RatString() != hashData.HashRate.RatString() { t.Fatalf("expected hash rate value of %v, got %v", hashData.HashRate, fetchedHashData.HashRate) } @@ -88,6 +88,12 @@ func testHashData(t *testing.T) { t.Fatalf("expected one hash data, got %d", len(dataset)) } + // Ensure the account id is a key of the hash data set returned. + _, ok := dataset[xID] + if !ok { + t.Fatalf("expected dataset to have %s as an account id key", xID) + } + newUpdatedOn := hashData.UpdatedOn + 100 hashData.UpdatedOn = newUpdatedOn diff --git a/pool/hub.go b/pool/hub.go index 7ab0582a..76765b8b 100644 --- a/pool/hub.go +++ b/pool/hub.go @@ -571,7 +571,8 @@ func (h *Hub) Run(ctx context.Context) { h.shutdown() } -// FetchClients returns all hash data from connected pool clients. +// FetchHashData returns all hash data from connected pool clients +// which have been updated in the last minute. func (h *Hub) FetchHashData() (map[string][]*HashData, error) { aMinuteAgo := time.Now().Add(-time.Minute).UnixNano() hashData, err := h.cfg.DB.listHashData(aMinuteAgo) diff --git a/pool/postgres.go b/pool/postgres.go index b3980179..a9179352 100644 --- a/pool/postgres.go +++ b/pool/postgres.go @@ -229,9 +229,10 @@ func decodeShareRows(rows *sql.Rows) ([]*Share, error) { // decodeHashDataRows deserializes the provided SQL rows into a slice of // HashData structs. -func decodeHashDataRows(rows *sql.Rows) ([]*HashData, error) { +func decodeHashDataRows(rows *sql.Rows) (map[string][]*HashData, error) { const funcName = "decodeHashDataRows" - var toReturn []*HashData + + toReturn := make(map[string][]*HashData) for rows.Next() { var uuid, accountID, miner, ip, hashRate string var updatedOn int64 @@ -243,8 +244,15 @@ func decodeHashDataRows(rows *sql.Rows) ([]*HashData, error) { return nil, errs.DBError(errs.Decode, desc) } - hashData := &HashData{uuid, accountID, miner, ip, hashRate, updatedOn} - toReturn = append(toReturn, hashData) + hashRat, ok := new(big.Rat).SetString(hashRate) + if !ok { + desc := fmt.Sprintf("%s: unable to decode big.Rat string: %v", + funcName, err) + return nil, errs.DBError(errs.Parse, desc) + } + + hashData := &HashData{uuid, accountID, miner, ip, hashRat, updatedOn} + toReturn[accountID] = append(toReturn[accountID], hashData) } err := rows.Err() @@ -992,7 +1000,8 @@ func (db *PostgresDB) persistHashData(hashData *HashData) error { const funcName = "persistHashData" _, err := db.DB.Exec(insertHashData, hashData.UUID, hashData.AccountID, - hashData.Miner, hashData.IP, hashData.HashRate, hashData.UpdatedOn) + hashData.Miner, hashData.IP, hashData.HashRate.RatString(), + hashData.UpdatedOn) if err != nil { var pqError *pq.Error @@ -1010,13 +1019,13 @@ func (db *PostgresDB) persistHashData(hashData *HashData) error { return nil } -// updateHashData persists the updated payment to the database. +// updateHashData persists the updated hash data to the database. func (db *PostgresDB) updateHashData(hashData *HashData) error { const funcName = "updateHashData" result, err := db.DB.Exec(updateHashData, hashData.UUID, hashData.AccountID, hashData.Miner, - hashData.IP, hashData.HashRate, hashData.UpdatedOn) + hashData.IP, hashData.HashRate.RatString(), hashData.UpdatedOn) if err != nil { return err } @@ -1053,11 +1062,18 @@ func (db *PostgresDB) fetchHashData(id string) (*HashData, error) { funcName, id, err) return nil, errs.DBError(errs.FetchEntry, desc) } - return &HashData{uuid, accountID, miner, ip, hashRate, updatedOn}, nil + + hashRat, ok := new(big.Rat).SetString(hashRate) + if !ok { + desc := fmt.Sprintf("%s: unable to decode big.Rat string: %v", + funcName, err) + return nil, errs.DBError(errs.Parse, desc) + } + + return &HashData{uuid, accountID, miner, ip, hashRat, updatedOn}, nil } -// listHashData fetches all hash data updated before the provided minimum time -// provided. +// listHashData fetches all hash data updated after the provided minimum time. func (db *PostgresDB) listHashData(minNano int64) (map[string][]*HashData, error) { const funcName = "listHashData" rows, err := db.DB.Query(listHashData, minNano) @@ -1067,21 +1083,16 @@ func (db *PostgresDB) listHashData(minNano int64) (map[string][]*HashData, error return nil, errs.DBError(errs.FetchEntry, desc) } - data, err := decodeHashDataRows(rows) + hashData, err := decodeHashDataRows(rows) if err != nil { return nil, err } - hashData := make(map[string][]*HashData) - for _, entry := range data { - hashData[entry.AccountID] = append(hashData[entry.AccountID], entry) - } - return hashData, nil } -// pruneHashData prunes all hash data that have not been since the provided -// minimum time. +// pruneHashData prunes all hash data that have not been updated since +// the provided minimum time. func (db *PostgresDB) pruneHashData(minNano int64) error { const funcName = "pruneHashData"