Use common.JSONNumber instead of json.Number

pull/419/head
Martin Boehm 2020-05-10 00:03:22 +02:00
parent c3d58f0649
commit ee3217aba8
11 changed files with 147 additions and 122 deletions

View File

@ -370,19 +370,19 @@ type Blocks struct {
// BlockInfo contains extended block header data and a list of block txids
type BlockInfo struct {
Hash string `json:"hash"`
Prev string `json:"previousBlockHash,omitempty"`
Next string `json:"nextBlockHash,omitempty"`
Height uint32 `json:"height"`
Confirmations int `json:"confirmations"`
Size int `json:"size"`
Time int64 `json:"time,omitempty"`
Version json.Number `json:"version"`
MerkleRoot string `json:"merkleRoot"`
Nonce string `json:"nonce"`
Bits string `json:"bits"`
Difficulty string `json:"difficulty"`
Txids []string `json:"tx,omitempty"`
Hash string `json:"hash"`
Prev string `json:"previousBlockHash,omitempty"`
Next string `json:"nextBlockHash,omitempty"`
Height uint32 `json:"height"`
Confirmations int `json:"confirmations"`
Size int `json:"size"`
Time int64 `json:"time,omitempty"`
Version common.JSONNumber `json:"version"`
MerkleRoot string `json:"merkleRoot"`
Nonce string `json:"nonce"`
Bits string `json:"bits"`
Difficulty string `json:"difficulty"`
Txids []string `json:"tx,omitempty"`
}
// Block contains information about block

View File

@ -9,6 +9,7 @@ import (
"github.com/gogo/protobuf/proto"
"github.com/golang/glog"
"github.com/juju/errors"
"github.com/trezor/blockbook/common"
)
// BaseParser implements data parsing/handling functionality base for all other parsers
@ -39,9 +40,9 @@ func (p *BaseParser) GetAddrDescForUnknownInput(tx *Tx, input int) AddressDescri
const zeros = "0000000000000000000000000000000000000000"
// AmountToBigInt converts amount in json.Number (string) to big.Int
// AmountToBigInt converts amount in common.JSONNumber (string) to big.Int
// it uses string operations to avoid problems with rounding
func (p *BaseParser) AmountToBigInt(n json.Number) (big.Int, error) {
func (p *BaseParser) AmountToBigInt(n common.JSONNumber) (big.Int, error) {
var r big.Int
s := string(n)
i := strings.IndexByte(s, '.')

View File

@ -1,9 +1,12 @@
// +build unittest
package bchain
import (
"encoding/json"
"math/big"
"testing"
"github.com/trezor/blockbook/common"
)
func NewBaseParser(adp int) *BaseParser {
@ -44,7 +47,7 @@ func TestBaseParser_AmountToDecimalString(t *testing.T) {
func TestBaseParser_AmountToBigInt(t *testing.T) {
for _, tt := range amounts {
t.Run(tt.s, func(t *testing.T) {
got, err := NewBaseParser(tt.adp).AmountToBigInt(json.Number(tt.s))
got, err := NewBaseParser(tt.adp).AmountToBigInt(common.JSONNumber(tt.s))
if err != nil {
t.Errorf("BaseParser.AmountToBigInt() error = %v", err)
return

View File

@ -17,6 +17,7 @@ import (
"github.com/juju/errors"
"github.com/martinboehm/btcd/wire"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/common"
)
// BitcoinRPC is an interface to JSON-RPC bitcoind service.
@ -237,13 +238,13 @@ type CmdGetBlockChainInfo struct {
type ResGetBlockChainInfo struct {
Error *bchain.RPCError `json:"error"`
Result struct {
Chain string `json:"chain"`
Blocks int `json:"blocks"`
Headers int `json:"headers"`
Bestblockhash string `json:"bestblockhash"`
Difficulty json.Number `json:"difficulty"`
SizeOnDisk int64 `json:"size_on_disk"`
Warnings string `json:"warnings"`
Chain string `json:"chain"`
Blocks int `json:"blocks"`
Headers int `json:"headers"`
Bestblockhash string `json:"bestblockhash"`
Difficulty common.JSONNumber `json:"difficulty"`
SizeOnDisk int64 `json:"size_on_disk"`
Warnings string `json:"warnings"`
} `json:"result"`
}
@ -256,11 +257,11 @@ type CmdGetNetworkInfo struct {
type ResGetNetworkInfo struct {
Error *bchain.RPCError `json:"error"`
Result struct {
Version json.Number `json:"version"`
Subversion json.Number `json:"subversion"`
ProtocolVersion json.Number `json:"protocolversion"`
Timeoffset float64 `json:"timeoffset"`
Warnings string `json:"warnings"`
Version common.JSONNumber `json:"version"`
Subversion common.JSONNumber `json:"subversion"`
ProtocolVersion common.JSONNumber `json:"protocolversion"`
Timeoffset float64 `json:"timeoffset"`
Warnings string `json:"warnings"`
} `json:"result"`
}
@ -358,8 +359,8 @@ type CmdEstimateSmartFee struct {
type ResEstimateSmartFee struct {
Error *bchain.RPCError `json:"error"`
Result struct {
Feerate json.Number `json:"feerate"`
Blocks int `json:"blocks"`
Feerate common.JSONNumber `json:"feerate"`
Blocks int `json:"blocks"`
} `json:"result"`
}
@ -373,8 +374,8 @@ type CmdEstimateFee struct {
}
type ResEstimateFee struct {
Error *bchain.RPCError `json:"error"`
Result json.Number `json:"result"`
Error *bchain.RPCError `json:"error"`
Result common.JSONNumber `json:"result"`
}
// sendrawtransaction

View File

@ -1,4 +1,4 @@
// build unittest
// +build unittest
package dash

View File

@ -20,6 +20,7 @@ import (
"github.com/juju/errors"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/bchain/coins/btc"
"github.com/trezor/blockbook/common"
)
// voteBitYes defines the vote bit set when a given block validates the previous
@ -167,61 +168,61 @@ type GetBlockHashResult struct {
type GetBlockResult struct {
Error Error `json:"error"`
Result struct {
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
Size int32 `json:"size"`
Height uint32 `json:"height"`
Version json.Number `json:"version"`
MerkleRoot string `json:"merkleroot"`
StakeRoot string `json:"stakeroot"`
RawTx []RawTx `json:"rawtx"`
Tx []string `json:"tx,omitempty"`
STx []string `json:"stx,omitempty"`
Time int64 `json:"time"`
Nonce json.Number `json:"nonce"`
VoteBits uint16 `json:"votebits"`
FinalState string `json:"finalstate"`
Voters uint16 `json:"voters"`
FreshStake uint8 `json:"freshstake"`
Revocations uint8 `json:"revocations"`
PoolSize uint32 `json:"poolsize"`
Bits string `json:"bits"`
SBits float64 `json:"sbits"`
ExtraData string `json:"extradata"`
StakeVersion uint32 `json:"stakeversion"`
Difficulty float64 `json:"difficulty"`
ChainWork string `json:"chainwork"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
Size int32 `json:"size"`
Height uint32 `json:"height"`
Version common.JSONNumber `json:"version"`
MerkleRoot string `json:"merkleroot"`
StakeRoot string `json:"stakeroot"`
RawTx []RawTx `json:"rawtx"`
Tx []string `json:"tx,omitempty"`
STx []string `json:"stx,omitempty"`
Time int64 `json:"time"`
Nonce common.JSONNumber `json:"nonce"`
VoteBits uint16 `json:"votebits"`
FinalState string `json:"finalstate"`
Voters uint16 `json:"voters"`
FreshStake uint8 `json:"freshstake"`
Revocations uint8 `json:"revocations"`
PoolSize uint32 `json:"poolsize"`
Bits string `json:"bits"`
SBits float64 `json:"sbits"`
ExtraData string `json:"extradata"`
StakeVersion uint32 `json:"stakeversion"`
Difficulty float64 `json:"difficulty"`
ChainWork string `json:"chainwork"`
PreviousHash string `json:"previousblockhash"`
NextHash string `json:"nextblockhash,omitempty"`
} `json:"result"`
}
type GetBlockHeaderResult struct {
Error Error `json:"error"`
Result struct {
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
Version json.Number `json:"version"`
MerkleRoot string `json:"merkleroot"`
StakeRoot string `json:"stakeroot"`
VoteBits uint16 `json:"votebits"`
FinalState string `json:"finalstate"`
Voters uint16 `json:"voters"`
FreshStake uint8 `json:"freshstake"`
Revocations uint8 `json:"revocations"`
PoolSize uint32 `json:"poolsize"`
Bits string `json:"bits"`
SBits float64 `json:"sbits"`
Height uint32 `json:"height"`
Size uint32 `json:"size"`
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
ExtraData string `json:"extradata"`
StakeVersion uint32 `json:"stakeversion"`
Difficulty float64 `json:"difficulty"`
ChainWork string `json:"chainwork"`
PreviousHash string `json:"previousblockhash,omitempty"`
NextHash string `json:"nextblockhash,omitempty"`
Hash string `json:"hash"`
Confirmations int64 `json:"confirmations"`
Version common.JSONNumber `json:"version"`
MerkleRoot string `json:"merkleroot"`
StakeRoot string `json:"stakeroot"`
VoteBits uint16 `json:"votebits"`
FinalState string `json:"finalstate"`
Voters uint16 `json:"voters"`
FreshStake uint8 `json:"freshstake"`
Revocations uint8 `json:"revocations"`
PoolSize uint32 `json:"poolsize"`
Bits string `json:"bits"`
SBits float64 `json:"sbits"`
Height uint32 `json:"height"`
Size uint32 `json:"size"`
Time int64 `json:"time"`
Nonce uint32 `json:"nonce"`
ExtraData string `json:"extradata"`
StakeVersion uint32 `json:"stakeversion"`
Difficulty float64 `json:"difficulty"`
ChainWork string `json:"chainwork"`
PreviousHash string `json:"previousblockhash,omitempty"`
NextHash string `json:"nextblockhash,omitempty"`
} `json:"result"`
}
@ -296,8 +297,8 @@ type EstimateSmartFeeResult struct {
}
type EstimateFeeResult struct {
Error Error `json:"error"`
Result json.Number `json:"result"`
Error Error `json:"error"`
Result common.JSONNumber `json:"result"`
}
type SendRawTransactionResult struct {
@ -636,7 +637,7 @@ func (d *DecredRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
Version: block.Result.Version,
Nonce: block.Result.Nonce,
Bits: block.Result.Bits,
Difficulty: json.Number(strconv.FormatFloat(block.Result.Difficulty, 'e', -1, 64)),
Difficulty: common.JSONNumber(strconv.FormatFloat(block.Result.Difficulty, 'e', -1, 64)),
Txids: block.Result.Tx,
}

View File

@ -17,6 +17,7 @@ import (
"github.com/golang/glog"
"github.com/juju/errors"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/common"
)
// EthereumNet type specifies the type of ethereum network
@ -569,8 +570,8 @@ func (b *EthereumRPC) GetBlockInfo(hash string) (*bchain.BlockInfo, error) {
}
return &bchain.BlockInfo{
BlockHeader: *bch,
Difficulty: json.Number(head.Difficulty),
Nonce: json.Number(head.Nonce),
Difficulty: common.JSONNumber(head.Difficulty),
Nonce: common.JSONNumber(head.Nonce),
Txids: txs.Transactions,
}, nil
}

View File

@ -1,8 +1,9 @@
// +build unittest
package nuls
import (
"encoding/hex"
"encoding/json"
"math/big"
"reflect"
"testing"
@ -11,6 +12,7 @@ import (
"github.com/martinboehm/btcutil/hdkeychain"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/bchain/coins/btc"
"github.com/trezor/blockbook/common"
)
var (
@ -41,7 +43,7 @@ func init() {
{
ValueSat: *big.NewInt(399999000000),
N: 0,
JsonValue: json.Number("0"),
JsonValue: common.JSONNumber("0"),
ScriptPubKey: bchain.ScriptPubKey{
Hex: "Nse4zpZHsUuU7h5ymv28pcGbwHju3joV",
Addresses: []string{
@ -73,7 +75,7 @@ func init() {
{
ValueSat: *big.NewInt(400000000000),
N: 0,
JsonValue: json.Number("0"),
JsonValue: common.JSONNumber("0"),
ScriptPubKey: bchain.ScriptPubKey{
Hex: "Nse4ikjE88g2BgsNwsswTdkSwiSrKjjS",
Addresses: []string{
@ -84,7 +86,7 @@ func init() {
{
ValueSat: *big.NewInt(7286565570000),
N: 1,
JsonValue: json.Number("0"),
JsonValue: common.JSONNumber("0"),
ScriptPubKey: bchain.ScriptPubKey{
Hex: "Nse119z2oSDJYkFkxmwYDiYtPfBeNkqi",
Addresses: []string{

View File

@ -7,6 +7,8 @@ import (
"errors"
"fmt"
"math/big"
"github.com/trezor/blockbook/common"
)
// ChainType is type of the blockchain
@ -68,9 +70,9 @@ type ScriptPubKey struct {
// Vout contains data about tx output
type Vout struct {
ValueSat big.Int
JsonValue json.Number `json:"value"`
N uint32 `json:"n"`
ScriptPubKey ScriptPubKey `json:"scriptPubKey"`
JsonValue common.JSONNumber `json:"value"`
N uint32 `json:"n"`
ScriptPubKey ScriptPubKey `json:"scriptPubKey"`
}
// Tx is blockchain transaction
@ -110,30 +112,30 @@ type BlockHeader struct {
// BlockInfo contains extended block header data and a list of block txids
type BlockInfo struct {
BlockHeader
Version json.Number `json:"version"`
MerkleRoot string `json:"merkleroot"`
Nonce json.Number `json:"nonce"`
Bits string `json:"bits"`
Difficulty json.Number `json:"difficulty"`
Txids []string `json:"tx,omitempty"`
Version common.JSONNumber `json:"version"`
MerkleRoot string `json:"merkleroot"`
Nonce common.JSONNumber `json:"nonce"`
Bits string `json:"bits"`
Difficulty common.JSONNumber `json:"difficulty"`
Txids []string `json:"tx,omitempty"`
}
// MempoolEntry is used to get data about mempool entry
type MempoolEntry struct {
Size uint32 `json:"size"`
FeeSat big.Int
Fee json.Number `json:"fee"`
Fee common.JSONNumber `json:"fee"`
ModifiedFeeSat big.Int
ModifiedFee json.Number `json:"modifiedfee"`
Time uint64 `json:"time"`
Height uint32 `json:"height"`
DescendantCount uint32 `json:"descendantcount"`
DescendantSize uint32 `json:"descendantsize"`
DescendantFees uint32 `json:"descendantfees"`
AncestorCount uint32 `json:"ancestorcount"`
AncestorSize uint32 `json:"ancestorsize"`
AncestorFees uint32 `json:"ancestorfees"`
Depends []string `json:"depends"`
ModifiedFee common.JSONNumber `json:"modifiedfee"`
Time uint64 `json:"time"`
Height uint32 `json:"height"`
DescendantCount uint32 `json:"descendantcount"`
DescendantSize uint32 `json:"descendantsize"`
DescendantFees uint32 `json:"descendantfees"`
AncestorCount uint32 `json:"ancestorcount"`
AncestorSize uint32 `json:"ancestorsize"`
AncestorFees uint32 `json:"ancestorfees"`
Depends []string `json:"depends"`
}
// ChainInfo is used to get information about blockchain
@ -267,9 +269,9 @@ type BlockChainParser interface {
MinimumCoinbaseConfirmations() int
// AmountToDecimalString converts amount in big.Int to string with decimal point in the correct place
AmountToDecimalString(a *big.Int) string
// AmountToBigInt converts amount in json.Number (string) to big.Int
// AmountToBigInt converts amount in common.JSONNumber (string) to big.Int
// it uses string operations to avoid problems with rounding
AmountToBigInt(n json.Number) (big.Int, error)
AmountToBigInt(n common.JSONNumber) (big.Int, error)
// address descriptor conversions
GetAddrDescFromVout(output *Vout) (AddressDescriptor, error)
GetAddrDescFromAddress(address string) (AddressDescriptor, error)

View File

@ -3,8 +3,6 @@ package common
import (
"encoding/json"
"strconv"
"github.com/golang/glog"
)
// JSONNumber is used instead of json.Number after upgrade to go 1.14
@ -36,7 +34,11 @@ func (c JSONNumber) String() string {
// MarshalJSON marsalls JSONNumber to []byte
// if possible, return a number without quotes, otherwise string value in quotes
// empty string is treated as number 0
func (c JSONNumber) MarshalJSON() ([]byte, error) {
if len(c) == 0 {
return []byte("0"), nil
}
if f, err := c.Float64(); err == nil {
return json.Marshal(f)
}
@ -53,6 +55,5 @@ func (c *JSONNumber) UnmarshalJSON(d []byte) error {
} else {
*c = JSONNumber(s)
}
glog.Info("JSONNumber ", s, ", ", *c)
return nil
}

View File

@ -1,3 +1,5 @@
// +build unittest
package common
import (
@ -16,8 +18,8 @@ func TestJSONNumber_MarshalJSON(t *testing.T) {
{"1", JSONNumber("1"), []byte("1"), false},
{"2", JSONNumber("12341234.43214123"), []byte("12341234.43214123"), false},
{"3", JSONNumber("123E55"), []byte("1.23e+57"), false},
{"NaN", JSONNumber("dsfafdasf"), []byte("\"dsfafdasf\""), false},
{"empty", JSONNumber(""), []byte("\"\""), false},
{"NaN", JSONNumber("dsfafdasf"), []byte(`"dsfafdasf"`), false},
{"empty", JSONNumber(""), []byte("0"), false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -36,17 +38,28 @@ func TestJSONNumber_MarshalJSON(t *testing.T) {
func TestJSONNumber_UnmarshalJSON(t *testing.T) {
tests := []struct {
name string
c *JSONNumber
d []byte
want JSONNumber
wantErr bool
}{
// TODO: Add test cases.
{"0", []byte("0"), JSONNumber("0"), false},
{"1", []byte("1"), JSONNumber("1"), false},
{"1 quotes", []byte(`"1"`), JSONNumber("1"), false},
{"2", []byte("12341234.43214123"), JSONNumber("12341234.43214123"), false},
{"3", []byte("1.23e+57"), JSONNumber("1.23e+57"), false},
{"NaN", []byte(`"dsfafdasf"`), JSONNumber("dsfafdasf"), false},
{"empty", []byte(`""`), JSONNumber(""), false},
{"really empty", []byte(""), JSONNumber(""), false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := tt.c.UnmarshalJSON(tt.d); (err != nil) != tt.wantErr {
var got JSONNumber
if err := got.UnmarshalJSON(tt.d); (err != nil) != tt.wantErr {
t.Errorf("JSONNumber.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("JSONNumber.UnmarshalJSON() = %v, want %v", got, tt.want)
}
})
}
}