fix: Convert big integers to float64
Large numbers can be returned by the Flexpool API reaching the `int64` limit. Blocks reward were seen as 0 ETH. Using `float64` instead. Also converting signed int64 to unsigned int64 for non-timestamp numbers. BREAKING CHANGE: please follow the upgrades instructions from 1.2 to 1.3 to convert such types in the database. Signed-off-by: Julien Riou <julien@riou.xyz>
This commit is contained in:
parent
ac0903cf9d
commit
3d4c049323
7 changed files with 63 additions and 25 deletions
16
UPGRADES.md
16
UPGRADES.md
|
@ -1,9 +1,19 @@
|
||||||
|
# General notes
|
||||||
|
|
||||||
|
In the next commands, you should replace `flexassistant.db` by the content of the `database_file` setting if it's has been changed.
|
||||||
|
|
||||||
|
# 1.2 to 1.3
|
||||||
|
|
||||||
|
The balance has reached maximum of **int64** type so the column should be converted to **real** to handle large numbers:
|
||||||
|
|
||||||
|
```
|
||||||
|
sqlite3 flexassistant.db < migrations/1.2_to_1.3.sql
|
||||||
|
```
|
||||||
|
|
||||||
# 1.0 to 1.1
|
# 1.0 to 1.1
|
||||||
|
|
||||||
Some numeric types have been updated from **float64** to **int64**. Upgrade the database types by running the following migration:
|
Some numeric types have been updated from **float64** to **int64**. Upgrade the database types by running the following migration:
|
||||||
|
|
||||||
```
|
```
|
||||||
sqlite3 flexassistant.db < migrations/1.0_to_1.1.sql
|
sqlite3 flexassistant.db < migrations/1.0_to_1.1.sql
|
||||||
```
|
```
|
||||||
|
|
||||||
And replace `flexassistant.db` by the content of the `database_file` setting if it's has been changed.
|
|
16
client.go
16
client.go
|
@ -66,12 +66,12 @@ func (f *FlexpoolClient) request(url string) ([]byte, error) {
|
||||||
type BalanceResponse struct {
|
type BalanceResponse struct {
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
Result struct {
|
Result struct {
|
||||||
Balance int64 `json:"balance"`
|
Balance float64 `json:"balance"`
|
||||||
} `json:"result"`
|
} `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MinerBalance returns the current unpaid balance
|
// MinerBalance returns the current unpaid balance
|
||||||
func (f *FlexpoolClient) MinerBalance(coin string, address string) (int64, error) {
|
func (f *FlexpoolClient) MinerBalance(coin string, address string) (float64, error) {
|
||||||
body, err := f.request(fmt.Sprintf("%s/miner/balance?coin=%s&address=%s", FlexpoolAPIURL, coin, address))
|
body, err := f.request(fmt.Sprintf("%s/miner/balance?coin=%s&address=%s", FlexpoolAPIURL, coin, address))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -87,9 +87,9 @@ type PaymentsResponse struct {
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
Result struct {
|
Result struct {
|
||||||
Data []struct {
|
Data []struct {
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
Value int64 `json:"value"`
|
Value float64 `json:"value"`
|
||||||
Timestamp int64 `json:"timestamp"`
|
Timestamp int64 `json:"timestamp"`
|
||||||
} `json:"data"`
|
} `json:"data"`
|
||||||
} `json:"result"`
|
} `json:"result"`
|
||||||
}
|
}
|
||||||
|
@ -165,9 +165,9 @@ type BlocksResponse struct {
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
Result struct {
|
Result struct {
|
||||||
Data []struct {
|
Data []struct {
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
Number int64 `json:"number"`
|
Number uint64 `json:"number"`
|
||||||
Reward int64 `json:"reward"`
|
Reward float64 `json:"reward"`
|
||||||
} `json:"data"`
|
} `json:"data"`
|
||||||
} `json:"result"`
|
} `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
2
main.go
2
main.go
|
@ -132,7 +132,7 @@ func main() {
|
||||||
log.Warnf("Could not fetch unpaid balance: %v", err)
|
log.Warnf("Could not fetch unpaid balance: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Debugf("Unpaid balance %d", balance)
|
log.Debugf("Unpaid balance %.0f", balance)
|
||||||
miner.Balance = balance
|
miner.Balance = balance
|
||||||
if miner.Balance != dbMiner.Balance {
|
if miner.Balance != dbMiner.Balance {
|
||||||
dbMiner.Balance = balance
|
dbMiner.Balance = balance
|
||||||
|
|
28
migrations/1.2_to_1.3.sql
Normal file
28
migrations/1.2_to_1.3.sql
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
-- Migrate from 1.2 to 1.3
|
||||||
|
-- SQLite doesn't support ALTER TABLE... ALTER TYPE
|
||||||
|
-- This migration file creates the new structures with "real" types
|
||||||
|
-- instead of "integer", move data to this new table then drop the old one.
|
||||||
|
|
||||||
|
-- miners
|
||||||
|
|
||||||
|
ALTER TABLE `miners` RENAME TO `miners_old`;
|
||||||
|
|
||||||
|
CREATE TABLE `miners` (
|
||||||
|
`id` integer,
|
||||||
|
`created_at` datetime,
|
||||||
|
`updated_at` datetime,
|
||||||
|
`deleted_at` datetime,
|
||||||
|
`coin` text,
|
||||||
|
`address` text NOT NULL UNIQUE,
|
||||||
|
`balance` real,
|
||||||
|
`last_payment_timestamp` integer,
|
||||||
|
PRIMARY KEY (`id`)
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO `miners` SELECT * FROM `miners_old`;
|
||||||
|
|
||||||
|
DROP TABLE `miners_old`;
|
||||||
|
|
||||||
|
CREATE INDEX `idx_miners_deleted_at` ON `miners`(`deleted_at`);
|
||||||
|
|
||||||
|
SELECT "Database migrated to 1.3"
|
6
miner.go
6
miner.go
|
@ -19,7 +19,7 @@ type Miner struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
Coin string
|
Coin string
|
||||||
Address string `gorm:"unique;not null"`
|
Address string `gorm:"unique;not null"`
|
||||||
Balance int64
|
Balance float64
|
||||||
LastPaymentTimestamp int64
|
LastPaymentTimestamp int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,12 +56,12 @@ func (m *Miner) String() string {
|
||||||
// Payment to store payment attributes
|
// Payment to store payment attributes
|
||||||
type Payment struct {
|
type Payment struct {
|
||||||
Hash string
|
Hash string
|
||||||
Value int64
|
Value float64
|
||||||
Timestamp int64
|
Timestamp int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPayment creates a Payment
|
// NewPayment creates a Payment
|
||||||
func NewPayment(hash string, value int64, timestamp int64) *Payment {
|
func NewPayment(hash string, value float64, timestamp int64) *Payment {
|
||||||
return &Payment{
|
return &Payment{
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
Value: value,
|
Value: value,
|
||||||
|
|
10
pool.go
10
pool.go
|
@ -10,7 +10,7 @@ import (
|
||||||
type Pool struct {
|
type Pool struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
Coin string `gorm:"unique;not null"`
|
Coin string `gorm:"unique;not null"`
|
||||||
LastBlockNumber int64
|
LastBlockNumber uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPool creates a Pool
|
// NewPool creates a Pool
|
||||||
|
@ -25,13 +25,13 @@ func (p *Pool) String() string {
|
||||||
|
|
||||||
// Block to store block attributes
|
// Block to store block attributes
|
||||||
type Block struct {
|
type Block struct {
|
||||||
Hash string `gorm:"unique;not null"`
|
Hash string `gorm:"unique;not null"`
|
||||||
Number int64 `gorm:"not null"`
|
Number uint64 `gorm:"not null"`
|
||||||
Reward int64 `gorm:"not null"`
|
Reward float64 `gorm:"not null"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlock creates a Block
|
// NewBlock creates a Block
|
||||||
func NewBlock(hash string, number int64, reward int64) *Block {
|
func NewBlock(hash string, number uint64, reward float64) *Block {
|
||||||
return &Block{
|
return &Block{
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
Number: number,
|
Number: number,
|
||||||
|
|
10
utils.go
10
utils.go
|
@ -12,7 +12,7 @@ const MojoToXCHDivider = 1000000000000
|
||||||
|
|
||||||
// ConvertCurrency divides the smallest unit of the currency to the currency itself
|
// ConvertCurrency divides the smallest unit of the currency to the currency itself
|
||||||
// Example: for "eth", convert from Weis to ETH
|
// Example: for "eth", convert from Weis to ETH
|
||||||
func ConvertCurrency(coin string, value int64) (float64, error) {
|
func ConvertCurrency(coin string, value float64) (float64, error) {
|
||||||
switch coin {
|
switch coin {
|
||||||
case "eth":
|
case "eth":
|
||||||
return ConvertWeis(value), nil
|
return ConvertWeis(value), nil
|
||||||
|
@ -24,13 +24,13 @@ func ConvertCurrency(coin string, value int64) (float64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertWeis converts the value from Weis to ETH
|
// ConvertWeis converts the value from Weis to ETH
|
||||||
func ConvertWeis(value int64) float64 {
|
func ConvertWeis(value float64) float64 {
|
||||||
return float64(value) / WeisToETHDivider
|
return value / WeisToETHDivider
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertMojo converts the value from Mojo to XCH
|
// ConvertMojo converts the value from Mojo to XCH
|
||||||
func ConvertMojo(value int64) float64 {
|
func ConvertMojo(value float64) float64 {
|
||||||
return float64(value) / MojoToXCHDivider
|
return value / MojoToXCHDivider
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertAction returns "Miner" for Ethereum and "Farmer" for Chia
|
// ConvertAction returns "Miner" for Ethereum and "Farmer" for Chia
|
||||||
|
|
Reference in a new issue