Browse Source

Add linter checks to GHA & Fix code to pass lints

Add linter checks to GHA & Fix code to pass lints.
The linters added are:
- whitespace: Tool for detection of leading and trailing whitespace
- gosec: Inspects source code for security problems
- gci: Gci control golang package import order and make it always deterministic
- misspell: Finds commonly misspelled English words in comments
- gomnd: An analyzer to detect magic numbers

The file utils/utils.go is excluded from the checks of gomnd, as uses magic numbers through the code
feature/sql-semaphore1
arnaucube 3 years ago
parent
commit
fd1e9c25ee
27 changed files with 95 additions and 75 deletions
  1. +2
    -2
      .github/workflows/lint.yml
  2. +7
    -0
      README.md
  3. +9
    -3
      common/account.go
  4. +3
    -1
      common/batch.go
  5. +4
    -2
      common/fee.go
  6. +1
    -1
      common/pooll2tx.go
  7. +0
    -1
      common/pooll2tx_test.go
  8. +2
    -2
      common/smartcontractparams.go
  9. +1
    -1
      common/syncstate.go
  10. +8
    -2
      common/tx.go
  11. +0
    -1
      common/tx_test.go
  12. +0
    -3
      coordinator/coordinator.go
  13. +0
    -1
      coordinator/proofpool.go
  14. +3
    -1
      db/historydb/historydb.go
  15. +2
    -2
      db/historydb/historydb_test.go
  16. +5
    -3
      db/l2db/l2db.go
  17. +1
    -1
      db/l2db/l2db_test.go
  18. +0
    -1
      db/statedb/statedb_test.go
  19. +3
    -3
      db/statedb/txprocessors.go
  20. +33
    -9
      eth/client.go
  21. +9
    -15
      priceupdater/priceupdater.go
  22. +0
    -2
      priceupdater/priceupdater_test.go
  23. +1
    -1
      test/lang.go
  24. +0
    -1
      test/txs.go
  25. +0
    -1
      txselector/txselector_test.go
  26. +1
    -6
      utils/utils.go
  27. +0
    -9
      utils/utils_test.go

+ 2
- 2
.github/workflows/lint.yml

@ -12,5 +12,5 @@ jobs:
uses: actions/checkout@v2
- name: Lint
run: |
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.24.0
$(go env GOPATH)/bin/golangci-lint run --timeout=5m
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.30.0
$(go env GOPATH)/bin/golangci-lint run --timeout=5m -E whitespace -E gosec -E gci -E misspell -E gomnd --max-same-issues 0

+ 7
- 0
README.md

@ -12,3 +12,10 @@ POSTGRES_PASS=yourpasswordhere; sudo docker run --rm --name hermez-db-test -p 54
```
POSTGRES_PASS=yourpasswordhere go test ./...
```
## Lint
- Install [golangci-lint](https://golangci-lint.run)
- Once installed, to check the lints
```
golangci-lint run --timeout=5m -E whitespace -E gosec -E gci -E misspell -E gomnd --max-same-issues 0
```

+ 9
- 3
common/account.go

@ -12,7 +12,13 @@ import (
cryptoUtils "github.com/iden3/go-iden3-crypto/utils"
)
const NLEAFELEMS = 4
const (
NLEAFELEMS = 4
// maxNonceValue is the maximum value that the Account.Nonce can have (40 bits: maxNonceValue=2**40-1)
maxNonceValue = 0xffffffffff
// maxBalanceBytes is the maximum bytes that can use the Account.Balance *big.Int
maxBalanceBytes = 24
)
// Account is a struct that gives information of the holdings of an address and a specific token. Is the data structure that generates the Value stored in the leaf of the MerkleTree
type Account struct {
@ -37,10 +43,10 @@ func (a *Account) String() string {
func (a *Account) Bytes() ([32 * NLEAFELEMS]byte, error) {
var b [32 * NLEAFELEMS]byte
if a.Nonce > 0xffffffffff {
if a.Nonce > maxNonceValue {
return b, fmt.Errorf("%s Nonce", ErrNumOverflow)
}
if len(a.Balance.Bytes()) > 24 {
if len(a.Balance.Bytes()) > maxBalanceBytes {
return b, fmt.Errorf("%s Balance", ErrNumOverflow)
}

+ 3
- 1
common/batch.go

@ -8,6 +8,8 @@ import (
ethCommon "github.com/ethereum/go-ethereum/common"
)
const batchNumBytesLen = 4
// Batch is a struct that represents Hermez network batch
type Batch struct {
BatchNum BatchNum `meddler:"batch_num"`
@ -33,7 +35,7 @@ func (bn BatchNum) Bytes() []byte {
// BatchNumFromBytes returns BatchNum from a []byte
func BatchNumFromBytes(b []byte) (BatchNum, error) {
if len(b) != 4 {
if len(b) != batchNumBytesLen {
return 0, fmt.Errorf("can not parse BatchNumFromBytes, bytes len %d, expected 4", len(b))
}
batchNum := binary.LittleEndian.Uint32(b[:4])

+ 4
- 2
common/fee.go

@ -1,6 +1,6 @@
package common
// Fee is a type that represents the percentage of tokens that will be payed in a transaction
// Fee is a type that represents the percentage of tokens that will be paid in a transaction
// to incentivaise the materialization of it
type Fee float64
@ -15,5 +15,7 @@ type RecommendedFee struct {
// FeeSelector is used to select a percentage from the FeePlan.
type FeeSelector uint8
const MAXFEEPLAN = 256
// FeePlan represents the fee model, a position in the array indicates the percentage of tokens paid in concept of fee for a transaction
var FeePlan = [256]float64{}
var FeePlan = [MAXFEEPLAN]float64{}

+ 1
- 1
common/pooll2tx.go

@ -17,7 +17,7 @@ type Nonce uint64
// Bytes returns a byte array of length 5 representing the Nonce
func (n Nonce) Bytes() ([5]byte, error) {
if n >= 1099511627776 { // 2**40bits
if n > maxNonceValue {
return [5]byte{}, ErrNonceOverflow
}
var nonceBytes [8]byte

+ 0
- 1
common/pooll2tx_test.go

@ -68,7 +68,6 @@ func TestTxCompressedData(t *testing.T) {
// test vector value generated from javascript implementation
assert.Equal(t, "6571340879233176732837827812956721483162819083004853354503", txCompressedData.String())
assert.Equal(t, "10c000000000b0000000a0009000000000008000000000007", hex.EncodeToString(txCompressedData.Bytes())[1:])
}
func TestHashToSign(t *testing.T) {

+ 2
- 2
common/smartcontractparams.go

@ -16,6 +16,6 @@ type SmartContractParameters struct {
ContractAddr ethCommon.Address // Ethereum address of the rollup smart contract
NLevels uint16 // Heigth of the SMT. This will determine the maximum number of accounts that can coexist in the Hermez network by 2^nLevels
MaxTxs uint16 // Max amount of txs that can be added in a batch, either L1 or L2
FeeL1Tx *big.Int // amount of eth (in wei) that has to be payed to do a L1 tx
FeeDeposit *big.Int // amount of eth (in wei) that has to be payed to do a deposit
FeeL1Tx *big.Int // amount of eth (in wei) that has to be paid to do a L1 tx
FeeDeposit *big.Int // amount of eth (in wei) that has to be paid to do a deposit
}

+ 1
- 1
common/syncstate.go

@ -4,7 +4,7 @@ import (
"time"
)
// SyncronizerState describes the syncronization progress of the smart contracts
// SyncronizerState describes the synchronization progress of the smart contracts
type SyncronizerState struct {
LastUpdate time.Time // last time this information was updated
CurrentBatchNum BatchNum // Last batch that was forged on the blockchain

+ 8
- 2
common/tx.go

@ -6,6 +6,12 @@ import (
"math/big"
)
const (
idxBytesLen = 4
// maxIdxValue is the maximum value that Idx can have (32 bits: maxIdxValue=2**32-1)
maxIdxValue = 0xffffffff
)
// Idx represents the account Index in the MerkleTree
type Idx uint32
@ -23,7 +29,7 @@ func (idx Idx) BigInt() *big.Int {
// IdxFromBytes returns Idx from a byte array
func IdxFromBytes(b []byte) (Idx, error) {
if len(b) != 4 {
if len(b) != idxBytesLen {
return 0, fmt.Errorf("can not parse Idx, bytes len %d, expected 4", len(b))
}
idx := binary.LittleEndian.Uint32(b[:4])
@ -32,7 +38,7 @@ func IdxFromBytes(b []byte) (Idx, error) {
// IdxFromBigInt converts a *big.Int to Idx type
func IdxFromBigInt(b *big.Int) (Idx, error) {
if b.Int64() > 0xffffffff { // 2**32-1
if b.Int64() > maxIdxValue {
return 0, ErrNumOverflow
}
return Idx(uint32(b.Int64())), nil

+ 0
- 1
common/tx_test.go

@ -19,5 +19,4 @@ func TestIdx(t *testing.T) {
assert.NotNil(t, err)
assert.Equal(t, ErrNumOverflow, err)
assert.Equal(t, Idx(0), i)
}

+ 0
- 3
coordinator/coordinator.go

@ -294,17 +294,14 @@ func (c *Coordinator) isForgeSequence() bool {
}
func (c *Coordinator) purgeRemoveByTimeout() error {
return nil
}
func (c *Coordinator) purgeInvalidDueToL2TxsSelection(l2Txs []*common.PoolL2Tx) error {
return nil
}
func (c *Coordinator) shouldL1L2Batch() bool {
return false
}

+ 0
- 1
coordinator/proofpool.go

@ -20,6 +20,5 @@ type ServerProofPool struct {
}
func (p *ServerProofPool) GetNextAvailable() (*ServerProofInfo, error) {
return nil, nil
}

+ 3
- 1
db/historydb/historydb.go

@ -7,7 +7,9 @@ import (
"github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/db"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq" // driver for postgres DB
//nolint:errcheck // driver for postgres DB
_ "github.com/lib/pq"
migrate "github.com/rubenv/sql-migrate"
"github.com/russross/meddler"
)

+ 2
- 2
db/historydb/historydb_test.go

@ -49,8 +49,8 @@ func TestBlocks(t *testing.T) {
// Generate fake blocks
blocks := genBlocks(fromBlock, toBlock)
// Insert blocks into DB
for _, block := range blocks {
err := historyDB.AddBlock(&block)
for i := 0; i < len(blocks); i++ {
err := historyDB.AddBlock(&blocks[i])
assert.NoError(t, err)
}
// Get all blocks from DB

+ 5
- 3
db/l2db/l2db.go

@ -10,7 +10,9 @@ import (
"github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/db"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq" // driver for postgres DB
//nolint:errcheck // driver for postgres DB
_ "github.com/lib/pq"
migrate "github.com/rubenv/sql-migrate"
"github.com/russross/meddler"
)
@ -26,7 +28,7 @@ type L2DB struct {
// NewL2DB creates a L2DB.
// More info on how to set dbDialect and dbArgs here: http://gorm.io/docs/connecting_to_the_database.html
// safetyPeriod is the ammount of blockchain blocks that must be waited before deleting anything (to avoid reorg problems).
// safetyPeriod is the amount of blockchain blocks that must be waited before deleting anything (to avoid reorg problems).
// maxTxs indicates the desired maximum amount of txs stored on the L2DB.
// TTL indicates the maximum amount of time that a tx can be in the L2DB
// (to prevent tx that won't ever be forged to stay there, will be used if maxTxs is exceeded).
@ -153,7 +155,7 @@ func (l2db *L2DB) UpdateTxs(txs []*common.PoolL2Tx) error {
return nil
}
// Reorg updates the state of txs that were updated in a batch that has been discarted due to a blockchian reorg.
// Reorg updates the state of txs that were updated in a batch that has been discarted due to a blockchain reorg.
// The state of the affected txs can change form Forged -> Pending or from Invalid -> Pending
func (l2db *L2DB) Reorg(lastValidBatch common.BatchNum) error {
// TODO: impl

+ 1
- 1
db/l2db/l2db_test.go

@ -122,7 +122,7 @@ func TestStartForging(t *testing.T) {
func genTxs(n int) []*common.PoolL2Tx {
// WARNING: This tx doesn't follow the protocol (signature, txID, ...)
// it's just to test geting/seting from/to the DB.
// it's just to test getting/setting from/to the DB.
// Type and RqTxCompressedData: not initialized because it's not stored
// on the DB and add noise when checking results.
txs := make([]*common.PoolL2Tx, 0, n)

+ 0
- 1
db/statedb/statedb_test.go

@ -32,7 +32,6 @@ func newAccount(t *testing.T, i int) *common.Account {
PublicKey: pk,
EthAddr: address,
}
}
func TestStateDBWithoutMT(t *testing.T) {

+ 3
- 3
db/statedb/txprocessors.go

@ -213,7 +213,7 @@ func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
if err != nil {
return err
}
// substract amount to the sender
// subtract amount to the sender
accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
// add amount to the receiver
accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
@ -247,7 +247,7 @@ func (s *StateDB) applyTransfer(tx *common.Tx) error {
// increment nonce
accSender.Nonce++
// substract amount to the sender
// subtract amount to the sender
accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
// add amount to the receiver
accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
@ -267,7 +267,7 @@ func (s *StateDB) applyTransfer(tx *common.Tx) error {
}
func (s *StateDB) applyExit(exitTree *merkletree.MerkleTree, tx *common.Tx) (*common.Account, error) {
// 0. substract tx.Amount from current Account in StateMT
// 0. subtract tx.Amount from current Account in StateMT
// add the tx.Amount into the Account (tx.FromIdx) in the ExitMT
acc, err := s.GetAccount(tx.FromIdx)
if err != nil {

+ 33
- 9
eth/client.go

@ -27,20 +27,45 @@ var (
const (
errStrDeploy = "deployment of %s failed: %w"
errStrWaitReceipt = "wait receipt of %s deploy failed: %w"
// default values
defaultCallGasLimit = 300000
defaultDeployGasLimit = 1000000
defaultGasPriceDiv = 100
defaultReceiptTimeout = 60
defaultIntervalReceiptLoop = 200
)
type Config struct {
CallGasLimit uint64
DeployGasLimit uint64
GasPriceDiv uint64
ReceiptTimeout time.Duration // in seconds
IntervalReceiptLoop time.Duration // in milliseconds
}
// Client is an ethereum client to call Smart Contract methods.
type Client struct {
client *ethclient.Client
account *accounts.Account
ks *ethKeystore.KeyStore
ReceiptTimeout time.Duration
config *Config
}
// NewClient creates a Client instance. The account is not mandatory (it can
// be nil). If the account is nil, CallAuth will fail with ErrAccountNil.
func NewClient(client *ethclient.Client, account *accounts.Account, ks *ethKeystore.KeyStore) *Client {
return &Client{client: client, account: account, ks: ks, ReceiptTimeout: 60 * time.Second}
func NewClient(client *ethclient.Client, account *accounts.Account, ks *ethKeystore.KeyStore, config *Config) *Client {
if config == nil {
config = &Config{
CallGasLimit: defaultCallGasLimit,
DeployGasLimit: defaultDeployGasLimit,
GasPriceDiv: defaultGasPriceDiv,
ReceiptTimeout: defaultReceiptTimeout,
IntervalReceiptLoop: defaultIntervalReceiptLoop,
}
}
return &Client{client: client, account: account, ks: ks, ReceiptTimeout: config.ReceiptTimeout * time.Second, config: config}
}
// BalanceAt retieves information about the default account
@ -67,7 +92,7 @@ func (c *Client) CallAuth(gasLimit uint64,
return nil, err
}
inc := new(big.Int).Set(gasPrice)
inc.Div(inc, new(big.Int).SetUint64(100))
inc.Div(inc, new(big.Int).SetUint64(c.config.GasPriceDiv))
gasPrice.Add(gasPrice, inc)
log.Debug("Transaction metadata", "gasPrice", gasPrice)
@ -77,7 +102,7 @@ func (c *Client) CallAuth(gasLimit uint64,
}
auth.Value = big.NewInt(0) // in wei
if gasLimit == 0 {
auth.GasLimit = uint64(300000) // in units
auth.GasLimit = c.config.CallGasLimit // in units
} else {
auth.GasLimit = gasLimit // in units
}
@ -99,14 +124,13 @@ type ContractData struct {
// Deploy a smart contract. `name` is used to log deployment information. fn
// is a wrapper to the deploy function generated by abigen. In case of error,
// the returned `ContractData` may have some parameters filled depending on the
// kind of error that ocurred.
// successfull.
// kind of error that occurred.
func (c *Client) Deploy(name string,
fn func(c *ethclient.Client, auth *bind.TransactOpts) (ethCommon.Address, *types.Transaction, interface{}, error)) (ContractData, error) {
var contractData ContractData
log.Info("Deploying", "contract", name)
tx, err := c.CallAuth(
1000000,
c.config.DeployGasLimit,
func(client *ethclient.Client, auth *bind.TransactOpts) (*types.Transaction, error) {
addr, tx, _, err := fn(client, auth)
if err != nil {
@ -162,7 +186,7 @@ func (c *Client) waitReceipt(tx *types.Transaction, ctx context.Context, timeout
if receipt != nil || time.Since(start) >= timeout {
break
}
time.Sleep(200 * time.Millisecond)
time.Sleep(c.config.IntervalReceiptLoop * time.Millisecond)
}
if receipt != nil && receipt.Status == types.ReceiptStatusFailed {
@ -174,7 +198,7 @@ func (c *Client) waitReceipt(tx *types.Transaction, ctx context.Context, timeout
log.Debug("Pendingtransaction / Wait receipt timeout", "tx", txid.Hex(), "lasterr", err)
return receipt, ErrReceiptNotReceived
}
log.Debug("Successfull transaction", "tx", txid.Hex())
log.Debug("Successful transaction", "tx", txid.Hex())
return receipt, err
}

+ 9
- 15
priceupdater/priceupdater.go

@ -10,6 +10,11 @@ import (
"github.com/dghubble/sling"
)
const (
defaultMaxIdleConns = 10
defaultIdleConnTimeout = 10
)
var (
// ErrSymbolDoesNotExistInDatabase is used when trying to get a token that is not in the DB
ErrSymbolDoesNotExistInDatabase = errors.New("symbol does not exist in database")
@ -39,20 +44,17 @@ type PriceUpdater struct {
// NewPriceUpdater is the constructor for the updater
func NewPriceUpdater(config ConfigPriceUpdater) PriceUpdater {
return PriceUpdater{
db: make(map[string]TokenInfo),
config: config,
}
}
// UpdatePrices is triggered by the Coordinator, and internally will update the token prices in the db
func (p *PriceUpdater) UpdatePrices() error {
tr := &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 10 * time.Second,
MaxIdleConns: defaultMaxIdleConns,
IdleConnTimeout: defaultIdleConnTimeout * time.Second,
DisableCompression: true,
}
httpClient := &http.Client{Transport: tr}
@ -61,12 +63,12 @@ func (p *PriceUpdater) UpdatePrices() error {
state := [10]float64{}
for _, tokenSymbol := range p.config.TokensList {
resp, err := client.New().Get("ticker/t" + tokenSymbol + "USD").ReceiveSuccess(&state)
if err != nil {
return err
}
if resp.StatusCode != 200 {
// if resp.StatusCode != 200 {
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("Unexpected response status code: %v", resp.StatusCode)
}
@ -77,7 +79,6 @@ func (p *PriceUpdater) UpdatePrices() error {
}
p.UpdateTokenInfo(tinfo)
}
return nil
@ -85,17 +86,14 @@ func (p *PriceUpdater) UpdatePrices() error {
// UpdateConfig allows to update the price-updater configuration
func (p *PriceUpdater) UpdateConfig(config ConfigPriceUpdater) {
p.mu.Lock()
defer p.mu.Unlock()
p.config = config
}
// Get one token information
func (p *PriceUpdater) Get(tokenSymbol string) (TokenInfo, error) {
var info TokenInfo
// Check if symbol exists in database
@ -107,12 +105,10 @@ func (p *PriceUpdater) Get(tokenSymbol string) (TokenInfo, error) {
}
return info, ErrSymbolDoesNotExistInDatabase
}
// GetPrices gets all the prices contained in the db
func (p *PriceUpdater) GetPrices() map[string]TokenInfo {
var info = make(map[string]TokenInfo)
p.mu.RLock()
@ -127,10 +123,8 @@ func (p *PriceUpdater) GetPrices() map[string]TokenInfo {
// UpdateTokenInfo updates one token info
func (p *PriceUpdater) UpdateTokenInfo(tokenInfo TokenInfo) {
p.mu.Lock()
defer p.mu.Unlock()
p.db[tokenInfo.Symbol] = tokenInfo
}

+ 0
- 2
priceupdater/priceupdater_test.go

@ -7,7 +7,6 @@ import (
)
func TestCon(t *testing.T) {
config := ConfigPriceUpdater{
RecommendedFee: 1,
@ -36,5 +35,4 @@ func TestCon(t *testing.T) {
prices := pud.GetPrices()
assert.Equal(t, prices["ETH"], info)
assert.Equal(t, prices["NEC"], info2)
}

+ 1
- 1
test/lang.go

@ -313,7 +313,7 @@ func (p *Parser) parseLine() (*Instruction, error) {
c.Literal += line
return c, err
}
if fee > 255 {
if fee > common.MAXFEEPLAN-1 {
line, _ := p.s.r.ReadString('\n')
c.Literal += line
return c, fmt.Errorf("Fee %d can not be bigger than 255", fee)

+ 0
- 1
test/txs.go

@ -143,7 +143,6 @@ func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]*common.L1Tx,
default:
continue
}
}
l1Txs = append(l1Txs, batchL1Txs)
coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)

+ 0
- 1
txselector/txselector_test.go

@ -7,7 +7,6 @@ import (
"github.com/hermeznetwork/hermez-node/db/l2db"
"github.com/hermeznetwork/hermez-node/db/statedb"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

+ 1
- 6
utils/utils.go

@ -1,3 +1,4 @@
//nolint:gomnd
package utils
import (
@ -33,9 +34,7 @@ func (fl16 *Float16) BigInt() *big.Int {
res := m.Mul(m, exp)
if e5 != 0 && e.Cmp(big.NewInt(0)) != 0 {
res.Add(res, exp.Div(exp, big.NewInt(2)))
}
return res
}
@ -56,11 +55,9 @@ func floorFix2Float(_f *big.Int) Float16 {
s := big.NewInt(0).Rsh(m, 10)
for s.Cmp(zero) != 0 {
m.Div(m, ten)
s.Rsh(m, 10)
e++
}
return Float16(m.Int64() | e<<11)
@ -98,13 +95,11 @@ func NewFloat16(f *big.Int) (Float16, error) {
d3 := big.NewInt(0).Abs(fi3.Sub(fi3, f))
if d.Cmp(d3) == 1 {
res = fl3
}
// Do rounding check
if res.BigInt().Cmp(f) == 0 {
return res, nil
}
return res, ErrRoundingLoss

+ 0
- 9
utils/utils_test.go

@ -8,7 +8,6 @@ import (
)
func TestConversions(t *testing.T) {
testVector := map[Float16]string{
0x307B: "123000000",
0x1DC6: "454500",
@ -24,7 +23,6 @@ func TestConversions(t *testing.T) {
}
for test := range testVector {
fix := test.BigInt()
assert.Equal(t, fix.String(), testVector[test])
@ -37,13 +35,10 @@ func TestConversions(t *testing.T) {
fx2 := fl.BigInt()
assert.Equal(t, fx2.String(), testVector[test])
}
}
func TestFloorFix2Float(t *testing.T) {
testVector := map[string]Float16{
"87999990000000000": 0x776f,
"87950000000000001": 0x776f,
@ -52,16 +47,13 @@ func TestFloorFix2Float(t *testing.T) {
}
for test := range testVector {
bi := big.NewInt(0)
bi.SetString(test, 10)
testFloat := NewFloat16Floor(bi)
assert.Equal(t, testFloat, testVector[test])
}
}
func TestConversionLosses(t *testing.T) {
@ -94,7 +86,6 @@ func TestConversionLosses(t *testing.T) {
assert.Equal(t, ErrRoundingLoss, err)
c = b.BigInt()
assert.NotEqual(t, c, a)
}
func BenchmarkFloat16(b *testing.B) {

Loading…
Cancel
Save