From e4c3339c911140bf2ab74b35c91a9ceff5a214e0 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Tue, 1 Dec 2020 11:40:58 +0300 Subject: [PATCH 1/3] util: move `Fixed8` to encoding/fixedn package --- cli/flags/fixed8.go | 10 +++---- cli/flags/fixed8_test.go | 10 +++---- cli/nep17_test.go | 10 +++---- cli/smartcontract/smart_contract.go | 3 +- cli/wallet/nep17.go | 5 ++-- pkg/core/helper_test.go | 5 ++-- pkg/core/state/notification_event.go | 5 ++-- pkg/core/transaction/transaction.go | 29 ++++++++++---------- pkg/core/transaction/transaction_test.go | 5 ++-- pkg/{util => encoding/fixedn}/fixed8.go | 2 +- pkg/{util => encoding/fixedn}/fixed8_test.go | 2 +- pkg/rpc/client/rpc.go | 7 +++-- pkg/rpc/client/rpc_test.go | 3 +- pkg/rpc/response/result/invoke.go | 6 ++-- pkg/rpc/response/result/invoke_test.go | 4 +-- pkg/rpc/rpc_config.go | 10 ++++--- 16 files changed, 63 insertions(+), 53 deletions(-) rename pkg/{util => encoding/fixedn}/fixed8.go (99%) rename pkg/{util => encoding/fixedn}/fixed8_test.go (99%) diff --git a/cli/flags/fixed8.go b/cli/flags/fixed8.go index 919652fb8..2f4a16d76 100644 --- a/cli/flags/fixed8.go +++ b/cli/flags/fixed8.go @@ -4,13 +4,13 @@ import ( "flag" "strings" - "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/urfave/cli" ) // Fixed8 is a wrapper for Uint160 with flag.Value methods. type Fixed8 struct { - Value util.Fixed8 + Value fixedn.Fixed8 } // Fixed8Flag is a flag with type string. @@ -32,7 +32,7 @@ func (a Fixed8) String() string { // Set implements flag.Value interface. func (a *Fixed8) Set(s string) error { - f, err := util.Fixed8FromString(s) + f, err := fixedn.Fixed8FromString(s) if err != nil { return cli.NewExitError(err, 1) } @@ -41,7 +41,7 @@ func (a *Fixed8) Set(s string) error { } // Fixed8 casts address to util.Fixed8. -func (a *Fixed8) Fixed8() util.Fixed8 { +func (a *Fixed8) Fixed8() fixedn.Fixed8 { return a.Value } @@ -70,6 +70,6 @@ func (f Fixed8Flag) Apply(set *flag.FlagSet) { } // Fixed8FromContext returns parsed util.Fixed8 value provided flag name. -func Fixed8FromContext(ctx *cli.Context, name string) util.Fixed8 { +func Fixed8FromContext(ctx *cli.Context, name string) fixedn.Fixed8 { return ctx.Generic(name).(*Fixed8).Value } diff --git a/cli/flags/fixed8_test.go b/cli/flags/fixed8_test.go index 62004b1c4..3eb344504 100644 --- a/cli/flags/fixed8_test.go +++ b/cli/flags/fixed8_test.go @@ -5,12 +5,12 @@ import ( "io/ioutil" "testing" - "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/stretchr/testify/require" ) func TestFixed8_String(t *testing.T) { - value := util.Fixed8(123) + value := fixedn.Fixed8(123) f := Fixed8{ Value: value, } @@ -19,7 +19,7 @@ func TestFixed8_String(t *testing.T) { } func TestFixed8_Set(t *testing.T) { - value := util.Fixed8(123) + value := fixedn.Fixed8(123) f := Fixed8{} require.Error(t, f.Set("not-a-fixed8")) @@ -30,10 +30,10 @@ func TestFixed8_Set(t *testing.T) { func TestFixed8_Fixed8(t *testing.T) { f := Fixed8{ - Value: util.Fixed8(123), + Value: fixedn.Fixed8(123), } - require.Equal(t, util.Fixed8(123), f.Fixed8()) + require.Equal(t, fixedn.Fixed8(123), f.Fixed8()) } func TestFixed8Flag_String(t *testing.T) { diff --git a/cli/nep17_test.go b/cli/nep17_test.go index 78ecb478c..a5ca20494 100644 --- a/cli/nep17_test.go +++ b/cli/nep17_test.go @@ -10,7 +10,7 @@ import ( "testing" "github.com/nspcc-dev/neo-go/pkg/encoding/address" - "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/stretchr/testify/require" ) @@ -47,7 +47,7 @@ func TestNEP17Balance(t *testing.T) { e.checkNextLine(t, "^\\s*Account\\s+"+validatorAddr) e.checkNextLine(t, "^\\s*GAS:\\s+GAS \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)") b := e.Chain.GetUtilityTokenBalance(validatorHash) - e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+util.Fixed8(b.Int64()).String()) + e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(b.Int64()).String()) }) t.Run("all accounts", func(t *testing.T) { e.Run(t, cmdbase...) @@ -56,7 +56,7 @@ func TestNEP17Balance(t *testing.T) { e.checkNextLine(t, "^Account "+address.Uint160ToString(addr1)) e.checkNextLine(t, "^\\s*GAS:\\s+GAS \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)") balance := e.Chain.GetUtilityTokenBalance(addr1) - e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+util.Fixed8(balance.Int64()).String()) + e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()) e.checkNextLine(t, "^\\s*Updated:") e.checkNextLine(t, "^\\s*$") @@ -74,7 +74,7 @@ func TestNEP17Balance(t *testing.T) { if strings.Contains(line, "GAS") { e.checkLine(t, line, "^\\s*GAS:\\s+GAS \\("+e.Chain.UtilityTokenHash().StringLE()+"\\)") balance = e.Chain.GetUtilityTokenBalance(addr3) - e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+util.Fixed8(balance.Int64()).String()) + e.checkNextLine(t, "^\\s*Amount\\s*:\\s*"+fixedn.Fixed8(balance.Int64()).String()) e.checkNextLine(t, "^\\s*Updated:") } else { balance, index := e.Chain.GetGoverningTokenBalance(validatorHash) @@ -156,7 +156,7 @@ func TestNEP17MultiTransfer(t *testing.T) { b, _ := e.Chain.GetGoverningTokenBalance(privs[0].GetScriptHash()) require.Equal(t, big.NewInt(42), b) b = e.Chain.GetUtilityTokenBalance(privs[1].GetScriptHash()) - require.Equal(t, big.NewInt(int64(util.Fixed8FromInt64(7))), b) + require.Equal(t, big.NewInt(int64(fixedn.Fixed8FromInt64(7))), b) b, _ = e.Chain.GetGoverningTokenBalance(privs[2].GetScriptHash()) require.Equal(t, big.NewInt(13), b) } diff --git a/cli/smartcontract/smart_contract.go b/cli/smartcontract/smart_contract.go index 8f37467c2..4f90d9c7c 100644 --- a/cli/smartcontract/smart_contract.go +++ b/cli/smartcontract/smart_contract.go @@ -19,6 +19,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/encoding/address" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/rpc/request" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result" "github.com/nspcc-dev/neo-go/pkg/smartcontract" @@ -446,7 +447,7 @@ func invokeFunction(ctx *cli.Context) error { func invokeInternal(ctx *cli.Context, signAndPush bool) error { var ( err error - gas util.Fixed8 + gas fixedn.Fixed8 operation string params = make([]smartcontract.Parameter, 0) paramsStart = 1 diff --git a/cli/wallet/nep17.go b/cli/wallet/nep17.go index 40f32d560..8257d4019 100644 --- a/cli/wallet/nep17.go +++ b/cli/wallet/nep17.go @@ -9,6 +9,7 @@ import ( "github.com/nspcc-dev/neo-go/cli/options" "github.com/nspcc-dev/neo-go/cli/paramcontext" "github.com/nspcc-dev/neo-go/pkg/encoding/address" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/rpc/client" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/wallet" @@ -390,7 +391,7 @@ func multiTransferNEP17(ctx *cli.Context) error { if err != nil { return cli.NewExitError(fmt.Errorf("invalid address: '%s'", ss[1]), 1) } - amount, err := util.FixedNFromString(ss[2], int(token.Decimals)) + amount, err := fixedn.FixedNFromString(ss[2], int(token.Decimals)) if err != nil { return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1) } @@ -437,7 +438,7 @@ func transferNEP17(ctx *cli.Context) error { } } - amount, err := util.FixedNFromString(ctx.String("amount"), int(token.Decimals)) + amount, err := fixedn.FixedNFromString(ctx.String("amount"), int(token.Decimals)) if err != nil { return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1) } diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index e63207516..e1b6a6de7 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -22,6 +22,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" @@ -198,7 +199,7 @@ func TestCreateBasicChain(t *testing.T) { acc0 := wallet.NewAccountFromPrivateKey(priv0) // Prepare some transaction for future submission. - txSendRaw := newNEP17Transfer(bc.contracts.NEO.Hash, priv0ScriptHash, priv1.GetScriptHash(), int64(util.Fixed8FromInt64(1000))) + txSendRaw := newNEP17Transfer(bc.contracts.NEO.Hash, priv0ScriptHash, priv1.GetScriptHash(), int64(fixedn.Fixed8FromInt64(1000))) txSendRaw.ValidUntilBlock = transaction.MaxValidUntilBlockIncrement txSendRaw.Nonce = 0x1234 txSendRaw.Signers = []transaction.Signer{{ @@ -245,7 +246,7 @@ func initBasicChain(t *testing.T, bc *Blockchain) { txMoveNeo, err := testchain.NewTransferFromOwner(bc, neoHash, priv0ScriptHash, neoAmount, getNextNonce(), validUntilBlock) require.NoError(t, err) // Move some GAS to one simple account. - txMoveGas, err := testchain.NewTransferFromOwner(bc, gasHash, priv0ScriptHash, int64(util.Fixed8FromInt64(1000)), + txMoveGas, err := testchain.NewTransferFromOwner(bc, gasHash, priv0ScriptHash, int64(fixedn.Fixed8FromInt64(1000)), getNextNonce(), validUntilBlock) require.NoError(t, err) diff --git a/pkg/core/state/notification_event.go b/pkg/core/state/notification_event.go index e4e1a846f..4caf4bdc2 100644 --- a/pkg/core/state/notification_event.go +++ b/pkg/core/state/notification_event.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" @@ -173,7 +174,7 @@ type Execution struct { type executionAux struct { Trigger string `json:"trigger"` VMState string `json:"vmstate"` - GasConsumed util.Fixed8 `json:"gasconsumed,string"` + GasConsumed fixedn.Fixed8 `json:"gasconsumed,string"` Stack json.RawMessage `json:"stack"` Events []NotificationEvent `json:"notifications"` FaultException string `json:"exception,omitempty"` @@ -202,7 +203,7 @@ func (e Execution) MarshalJSON() ([]byte, error) { return json.Marshal(&executionAux{ Trigger: e.Trigger.String(), VMState: e.VMState.String(), - GasConsumed: util.Fixed8(e.GasConsumed), + GasConsumed: fixedn.Fixed8(e.GasConsumed), Stack: st, Events: e.Events, FaultException: e.FaultException, diff --git a/pkg/core/transaction/transaction.go b/pkg/core/transaction/transaction.go index d0f79d44e..95ce8e664 100644 --- a/pkg/core/transaction/transaction.go +++ b/pkg/core/transaction/transaction.go @@ -10,6 +10,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/encoding/address" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/util" ) @@ -301,18 +302,18 @@ func (t *Transaction) Sender() util.Uint160 { // transactionJSON is a wrapper for Transaction and // used for correct marhalling of transaction.Data type transactionJSON struct { - TxID util.Uint256 `json:"hash"` - Size int `json:"size"` - Version uint8 `json:"version"` - Nonce uint32 `json:"nonce"` - Sender string `json:"sender"` - SystemFee util.Fixed8 `json:"sysfee,string"` - NetworkFee util.Fixed8 `json:"netfee,string"` - ValidUntilBlock uint32 `json:"validuntilblock"` - Attributes []Attribute `json:"attributes"` - Signers []Signer `json:"signers"` - Script []byte `json:"script"` - Scripts []Witness `json:"witnesses"` + TxID util.Uint256 `json:"hash"` + Size int `json:"size"` + Version uint8 `json:"version"` + Nonce uint32 `json:"nonce"` + Sender string `json:"sender"` + SystemFee fixedn.Fixed8 `json:"sysfee,string"` + NetworkFee fixedn.Fixed8 `json:"netfee,string"` + ValidUntilBlock uint32 `json:"validuntilblock"` + Attributes []Attribute `json:"attributes"` + Signers []Signer `json:"signers"` + Script []byte `json:"script"` + Scripts []Witness `json:"witnesses"` } // MarshalJSON implements json.Marshaler interface. @@ -328,8 +329,8 @@ func (t *Transaction) MarshalJSON() ([]byte, error) { Signers: t.Signers, Script: t.Script, Scripts: t.Scripts, - SystemFee: util.Fixed8(t.SystemFee), - NetworkFee: util.Fixed8(t.NetworkFee), + SystemFee: fixedn.Fixed8(t.SystemFee), + NetworkFee: fixedn.Fixed8(t.NetworkFee), } return json.Marshal(tx) } diff --git a/pkg/core/transaction/transaction_test.go b/pkg/core/transaction/transaction_test.go index 4df141aa8..587bc48a4 100644 --- a/pkg/core/transaction/transaction_test.go +++ b/pkg/core/transaction/transaction_test.go @@ -7,6 +7,7 @@ import ( "math" "testing" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -119,8 +120,8 @@ func TestMarshalUnmarshalJSONInvocationTX(t *testing.T) { Script: []byte{1, 2, 3, 4}, Attributes: []Attribute{{Type: HighPriority}}, Scripts: []Witness{}, - SystemFee: int64(util.Fixed8FromFloat(123.45)), - NetworkFee: int64(util.Fixed8FromFloat(0.123)), + SystemFee: int64(fixedn.Fixed8FromFloat(123.45)), + NetworkFee: int64(fixedn.Fixed8FromFloat(0.123)), Trimmed: false, } diff --git a/pkg/util/fixed8.go b/pkg/encoding/fixedn/fixed8.go similarity index 99% rename from pkg/util/fixed8.go rename to pkg/encoding/fixedn/fixed8.go index c11badae7..80103b9d5 100644 --- a/pkg/util/fixed8.go +++ b/pkg/encoding/fixedn/fixed8.go @@ -1,4 +1,4 @@ -package util +package fixedn import ( "encoding/json" diff --git a/pkg/util/fixed8_test.go b/pkg/encoding/fixedn/fixed8_test.go similarity index 99% rename from pkg/util/fixed8_test.go rename to pkg/encoding/fixedn/fixed8_test.go index 8421b11fc..5560e6a4d 100644 --- a/pkg/util/fixed8_test.go +++ b/pkg/encoding/fixedn/fixed8_test.go @@ -1,4 +1,4 @@ -package util +package fixedn import ( "encoding/json" diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index 22ffeec8a..65da7f66f 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -13,6 +13,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/rpc/request" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result" @@ -170,10 +171,10 @@ func (c *Client) GetBlockHeaderVerbose(hash util.Uint256) (*result.Header, error } // GetBlockSysFee returns the system fees of the block, based on the specified index. -func (c *Client) GetBlockSysFee(index uint32) (util.Fixed8, error) { +func (c *Client) GetBlockSysFee(index uint32) (fixedn.Fixed8, error) { var ( params = request.NewRawParams(index) - resp util.Fixed8 + resp fixedn.Fixed8 ) if err := c.performRequest("getblocksysfee", params, &resp); err != nil { return resp, err @@ -473,7 +474,7 @@ func (c *Client) SubmitBlock(b block.Block) (util.Uint256, error) { // SignAndPushInvocationTx signs and pushes given script as an invocation // transaction using given wif to sign it and spending the amount of gas // specified. It returns a hash of the invocation transaction and an error. -func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sysfee int64, netfee util.Fixed8, cosigners []transaction.Signer) (util.Uint256, error) { +func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sysfee int64, netfee fixedn.Fixed8, cosigners []transaction.Signer) (util.Uint256, error) { var txHash util.Uint256 var err error diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index b3c48eba3..8cffef5ff 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -22,6 +22,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/encoding/address" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/rpc/request" "github.com/nspcc-dev/neo-go/pkg/rpc/response/result" "github.com/nspcc-dev/neo-go/pkg/smartcontract" @@ -285,7 +286,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ }, serverResponse: `{"jsonrpc":"2.0","id":1,"result":"195500"}`, result: func(c *Client) interface{} { - return util.Fixed8FromInt64(195500) + return fixedn.Fixed8FromInt64(195500) }, }, }, diff --git a/pkg/rpc/response/result/invoke.go b/pkg/rpc/response/result/invoke.go index b070f4b27..922dcdcad 100644 --- a/pkg/rpc/response/result/invoke.go +++ b/pkg/rpc/response/result/invoke.go @@ -6,7 +6,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/core/transaction" - "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" ) @@ -26,7 +26,7 @@ type Invoke struct { type invokeAux struct { State string `json:"state"` - GasConsumed util.Fixed8 `json:"gasconsumed,string"` + GasConsumed fixedn.Fixed8 `json:"gasconsumed,string"` Script []byte `json:"script"` Stack json.RawMessage `json:"stack"` FaultException string `json:"exception,omitempty"` @@ -55,7 +55,7 @@ func (r Invoke) MarshalJSON() ([]byte, error) { } return json.Marshal(&invokeAux{ - GasConsumed: util.Fixed8(r.GasConsumed), + GasConsumed: fixedn.Fixed8(r.GasConsumed), Script: r.Script, State: r.State, Stack: st, diff --git a/pkg/rpc/response/result/invoke_test.go b/pkg/rpc/response/result/invoke_test.go index c6b3accc0..611831acb 100644 --- a/pkg/rpc/response/result/invoke_test.go +++ b/pkg/rpc/response/result/invoke_test.go @@ -6,7 +6,7 @@ import ( "math/big" "testing" - "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/stretchr/testify/require" ) @@ -14,7 +14,7 @@ import ( func TestInvoke_MarshalJSON(t *testing.T) { result := &Invoke{ State: "HALT", - GasConsumed: int64(util.Fixed8FromFloat(123.45)), + GasConsumed: int64(fixedn.Fixed8FromFloat(123.45)), Script: []byte{10}, Stack: []stackitem.Item{stackitem.NewBigInteger(big.NewInt(1))}, FaultException: "", diff --git a/pkg/rpc/rpc_config.go b/pkg/rpc/rpc_config.go index 30ecbf236..8647d6e83 100644 --- a/pkg/rpc/rpc_config.go +++ b/pkg/rpc/rpc_config.go @@ -1,6 +1,8 @@ package rpc -import "github.com/nspcc-dev/neo-go/pkg/util" +import ( + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" +) type ( // Config is an RPC service configuration information @@ -10,9 +12,9 @@ type ( EnableCORSWorkaround bool `yaml:"EnableCORSWorkaround"` // MaxGasInvoke is a maximum amount of gas which // can be spent during RPC call. - MaxGasInvoke util.Fixed8 `yaml:"MaxGasInvoke"` - Port uint16 `yaml:"Port"` - TLSConfig TLSConfig `yaml:"TLSConfig"` + MaxGasInvoke fixedn.Fixed8 `yaml:"MaxGasInvoke"` + Port uint16 `yaml:"Port"` + TLSConfig TLSConfig `yaml:"TLSConfig"` } // TLSConfig describes SSL/TLS configuration. From 56b23b718d338f300a5410efd8a5f4d4332429fa Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Mon, 30 Nov 2020 12:06:36 +0300 Subject: [PATCH 2/3] fixedn: allow to parse big decimals --- cli/wallet/nep17.go | 8 +-- pkg/encoding/fixedn/decimal.go | 80 +++++++++++++++++++++++++++++ pkg/encoding/fixedn/decimal_test.go | 51 ++++++++++++++++++ pkg/encoding/fixedn/fixed8.go | 30 +---------- pkg/encoding/fixedn/fixed8_test.go | 15 ------ 5 files changed, 137 insertions(+), 47 deletions(-) create mode 100644 pkg/encoding/fixedn/decimal.go create mode 100644 pkg/encoding/fixedn/decimal_test.go diff --git a/cli/wallet/nep17.go b/cli/wallet/nep17.go index 8257d4019..dd9006bd8 100644 --- a/cli/wallet/nep17.go +++ b/cli/wallet/nep17.go @@ -391,14 +391,14 @@ func multiTransferNEP17(ctx *cli.Context) error { if err != nil { return cli.NewExitError(fmt.Errorf("invalid address: '%s'", ss[1]), 1) } - amount, err := fixedn.FixedNFromString(ss[2], int(token.Decimals)) + amount, err := fixedn.FromString(ss[2], int(token.Decimals)) if err != nil { return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1) } recipients = append(recipients, client.TransferTarget{ Token: token.Hash, Address: addr, - Amount: amount, + Amount: amount.Int64(), }) } @@ -438,7 +438,7 @@ func transferNEP17(ctx *cli.Context) error { } } - amount, err := fixedn.FixedNFromString(ctx.String("amount"), int(token.Decimals)) + amount, err := fixedn.FromString(ctx.String("amount"), int(token.Decimals)) if err != nil { return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1) } @@ -446,7 +446,7 @@ func transferNEP17(ctx *cli.Context) error { return signAndSendTransfer(ctx, c, acc, []client.TransferTarget{{ Token: token.Hash, Address: to, - Amount: amount, + Amount: amount.Int64(), }}) } diff --git a/pkg/encoding/fixedn/decimal.go b/pkg/encoding/fixedn/decimal.go new file mode 100644 index 000000000..f26976e47 --- /dev/null +++ b/pkg/encoding/fixedn/decimal.go @@ -0,0 +1,80 @@ +package fixedn + +import ( + "errors" + "fmt" + "math/big" + "strconv" + "strings" +) + +const maxAllowedPrecision = 16 + +// ErrInvalidFormat is returned when decimal format is invalid. +var ErrInvalidFormat = errors.New("invalid decimal format") + +var _pow10 []*big.Int + +func init() { + var p = int64(1) + for i := 0; i <= maxAllowedPrecision; i++ { + _pow10 = append(_pow10, big.NewInt(p)) + p *= 10 + } +} + +func pow10(n int) *big.Int { + last := len(_pow10) - 1 + if n <= last { + return _pow10[n] + } + p := new(big.Int) + p.Mul(_pow10[last], _pow10[1]) + for i := last + 1; i < n; i++ { + p.Mul(p, _pow10[1]) + } + return p +} + +// ToString converts big decimal with specified precision to string. +func ToString(bi *big.Int, precision int) string { + var dp, fp big.Int + dp.QuoRem(bi, pow10(precision), &fp) + + var s = dp.String() + if fp.Sign() == 0 { + return s + } + frac := fp.Uint64() + trimmed := 0 + for ; frac%10 == 0; frac /= 10 { + trimmed++ + } + return s + "." + fmt.Sprintf("%0"+strconv.FormatUint(uint64(precision-trimmed), 10)+"d", frac) +} + +// FromString converts string to a big decimal with specified precision. +func FromString(s string, precision int) (*big.Int, error) { + parts := strings.SplitN(s, ".", 2) + bi, ok := new(big.Int).SetString(parts[0], 10) + if !ok { + return nil, ErrInvalidFormat + } + bi.Mul(bi, pow10(precision)) + if len(parts) == 1 { + return bi, nil + } + + if len(parts[1]) > precision { + return nil, ErrInvalidFormat + } + fp, ok := new(big.Int).SetString(parts[1], 10) + if !ok { + return nil, ErrInvalidFormat + } + fp.Mul(fp, pow10(precision-len(parts[1]))) + if bi.Sign() == -1 { + return bi.Sub(bi, fp), nil + } + return bi.Add(bi, fp), nil +} diff --git a/pkg/encoding/fixedn/decimal_test.go b/pkg/encoding/fixedn/decimal_test.go new file mode 100644 index 000000000..be676e85f --- /dev/null +++ b/pkg/encoding/fixedn/decimal_test.go @@ -0,0 +1,51 @@ +package fixedn + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestDecimalFromStringGood(t *testing.T) { + var testCases = []struct { + bi *big.Int + prec int + s string + }{ + {big.NewInt(123), 2, "1.23"}, + {big.NewInt(12300), 2, "123"}, + {big.NewInt(1234500000), 8, "12.345"}, + {big.NewInt(-12345), 3, "-12.345"}, + {big.NewInt(35), 8, "0.00000035"}, + {big.NewInt(1230), 5, "0.0123"}, + {big.NewInt(123456789), 20, "0.00000000000123456789"}, + } + for _, tc := range testCases { + t.Run(tc.s, func(t *testing.T) { + s := ToString(tc.bi, tc.prec) + require.Equal(t, tc.s, s) + + bi, err := FromString(s, tc.prec) + require.NoError(t, err) + require.Equal(t, tc.bi, bi) + }) + } +} + +func TestDecimalFromStringBad(t *testing.T) { + var errCases = []struct { + s string + prec int + }{ + {"12A", 1}, + {"12.345", 2}, + {"12.3A", 2}, + } + for _, tc := range errCases { + t.Run(tc.s, func(t *testing.T) { + _, err := FromString(tc.s, tc.prec) + require.Error(t, err) + }) + } +} diff --git a/pkg/encoding/fixedn/fixed8.go b/pkg/encoding/fixedn/fixed8.go index 80103b9d5..014a6e888 100644 --- a/pkg/encoding/fixedn/fixed8.go +++ b/pkg/encoding/fixedn/fixed8.go @@ -3,7 +3,6 @@ package fixedn import ( "encoding/json" "errors" - "math" "strconv" "strings" @@ -72,36 +71,11 @@ func Fixed8FromFloat(val float64) Fixed8 { // Fixed8FromString parses s which must be a fixed point number // with precision up to 10^-8 func Fixed8FromString(s string) (Fixed8, error) { - num, err := FixedNFromString(s, precision) + num, err := FromString(s, precision) if err != nil { return 0, err } - return Fixed8(num), err -} - -// FixedNFromString parses s which must be a fixed point number -// with precision 10^-d. -func FixedNFromString(s string, precision int) (int64, error) { - parts := strings.SplitN(s, ".", 2) - d := int64(math.Pow10(precision)) - ip, err := strconv.ParseInt(parts[0], 10, 64) - if err != nil { - return 0, errInvalidString - } else if len(parts) == 1 { - return ip * d, nil - } - - fp, err := strconv.ParseInt(parts[1], 10, 64) - if err != nil || fp >= d { - return 0, errInvalidString - } - for i := len(parts[1]); i < precision; i++ { - fp *= 10 - } - if ip < 0 { - return ip*d - fp, nil - } - return ip*d + fp, nil + return Fixed8(num.Int64()), err } // UnmarshalJSON implements the json unmarshaller interface. diff --git a/pkg/encoding/fixedn/fixed8_test.go b/pkg/encoding/fixedn/fixed8_test.go index 5560e6a4d..4bbaf2af2 100644 --- a/pkg/encoding/fixedn/fixed8_test.go +++ b/pkg/encoding/fixedn/fixed8_test.go @@ -8,7 +8,6 @@ import ( "github.com/nspcc-dev/neo-go/internal/testserdes" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "gopkg.in/yaml.v2" ) @@ -85,20 +84,6 @@ func TestFixed8FromString(t *testing.T) { assert.Error(t, err) } -func TestFixedNFromString(t *testing.T) { - val := "123.456" - num, err := FixedNFromString(val, 3) - require.NoError(t, err) - require.EqualValues(t, 123456, num) - - num, err = FixedNFromString(val, 4) - require.NoError(t, err) - require.EqualValues(t, 1234560, num) - - _, err = FixedNFromString(val, 2) - require.Error(t, err) -} - func TestSatoshi(t *testing.T) { satoshif8 := Satoshi() assert.Equal(t, "0.00000001", satoshif8.String()) From df801a853941a8b397c28513a20a7cbba786f28a Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Mon, 30 Nov 2020 12:20:13 +0300 Subject: [PATCH 3/3] rpc: marshal GAS in `getunclaimedgas` as decimal --- pkg/rpc/client/rpc_test.go | 2 +- pkg/rpc/response/result/unclaimed_gas.go | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index 8cffef5ff..3065538e5 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -643,7 +643,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (interface{}, error) { return c.GetUnclaimedGas("NMipL5VsNoLUBUJKPKLhxaEbPQVCZnyJyB") }, - serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"address":"NMipL5VsNoLUBUJKPKLhxaEbPQVCZnyJyB","unclaimed":"897299680935"}}`, + serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"address":"NMipL5VsNoLUBUJKPKLhxaEbPQVCZnyJyB","unclaimed":"8972.99680935"}}`, result: func(c *Client) interface{} { addr, err := address.StringToUint160("NMipL5VsNoLUBUJKPKLhxaEbPQVCZnyJyB") if err != nil { diff --git a/pkg/rpc/response/result/unclaimed_gas.go b/pkg/rpc/response/result/unclaimed_gas.go index af051acdd..c8e3183f7 100644 --- a/pkg/rpc/response/result/unclaimed_gas.go +++ b/pkg/rpc/response/result/unclaimed_gas.go @@ -2,10 +2,11 @@ package result import ( "encoding/json" - "errors" + "fmt" "math/big" "github.com/nspcc-dev/neo-go/pkg/encoding/address" + "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" "github.com/nspcc-dev/neo-go/pkg/util" ) @@ -25,7 +26,7 @@ type unclaimedGas struct { func (g UnclaimedGas) MarshalJSON() ([]byte, error) { gas := &unclaimedGas{ Address: address.Uint160ToString(g.Address), - Unclaimed: g.Unclaimed.String(), + Unclaimed: fixedn.ToString(&g.Unclaimed, 8), } return json.Marshal(gas) } @@ -36,9 +37,9 @@ func (g *UnclaimedGas) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, gas); err != nil { return err } - uncl, ok := new(big.Int).SetString(gas.Unclaimed, 10) - if !ok { - return errors.New("failed to convert unclaimed gas") + uncl, err := fixedn.FromString(gas.Unclaimed, 8) + if err != nil { + return fmt.Errorf("failed to convert unclaimed gas: %w", err) } g.Unclaimed = *uncl addr, err := address.StringToUint160(gas.Address)