From 8e29a200c049b4018fad80e1733a11958a9702bb Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Tue, 17 Nov 2020 12:28:28 +0300 Subject: [PATCH] rpc: adjust NEP5 transfers amount JSON marshalling This committ fixes the difference between Go and C# nodes: Go: ``` { "jsonrpc" : "2.0", "result" : { "received" : [ { "blockindex" : 65, "txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945", "transfernotifyindex" : 0, "timestamp" : 1605535020126, "transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY", "amount" : "29999999", "assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc" } ], "address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt", "sent" : [] }, "id" : 1 } ``` C#: ``` { "id" : 1, "result" : { "address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt", "sent" : [], "received" : [ { "transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY", "timestamp" : 1605535020126, "txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945", "blockindex" : 65, "transfernotifyindex" : 0, "amount" : "2999999900000000", "assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc" } ] }, "jsonrpc" : "2.0" } ``` --- pkg/rpc/server/server.go | 80 ++++++----------------------------- pkg/rpc/server/server_test.go | 30 ++++++------- 2 files changed, 29 insertions(+), 81 deletions(-) diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 4f7f05906..8afba33b3 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -554,16 +554,15 @@ func (s *Server) getNEP5Balances(ps request.Params) (interface{}, *response.Erro Balances: []result.NEP5Balance{}, } if as != nil { - cache := make(map[int32]decimals) + cache := make(map[int32]util.Uint160) for id, bal := range as.Trackers { - dec, err := s.getDecimals(id, cache) + h, err := s.getHash(id, cache) if err != nil { continue } - amount := amountToString(&bal.Balance, dec.Value) bs.Balances = append(bs.Balances, result.NEP5Balance{ - Asset: dec.Hash, - Amount: amount, + Asset: h, + Amount: bal.Balance.String(), LastUpdated: bal.LastUpdatedBlock, }) } @@ -637,7 +636,7 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err Received: []result.NEP5Transfer{}, Sent: []result.NEP5Transfer{}, } - cache := make(map[int32]decimals) + cache := make(map[int32]util.Uint160) var resCount, frameCount int err = s.chain.ForEachNEP5Transfer(u, func(tr *state.NEP5Transfer) (bool, error) { // Iterating from newest to oldest, not yet reached required @@ -656,25 +655,25 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err return true, nil } - d, err := s.getDecimals(tr.Asset, cache) + h, err := s.getHash(tr.Asset, cache) if err != nil { return false, err } transfer := result.NEP5Transfer{ Timestamp: tr.Timestamp, - Asset: d.Hash, + Asset: h, Index: tr.Block, TxHash: tr.Tx, } if tr.Amount.Sign() > 0 { // token was received - transfer.Amount = amountToString(&tr.Amount, d.Value) + transfer.Amount = tr.Amount.String() if !tr.From.Equals(util.Uint160{}) { transfer.Address = address.Uint160ToString(tr.From) } bs.Received = append(bs.Received, transfer) } else { - transfer.Amount = amountToString(new(big.Int).Neg(&tr.Amount), d.Value) + transfer.Amount = new(big.Int).Neg(&tr.Amount).String() if !tr.To.Equals(util.Uint160{}) { transfer.Address = address.Uint160ToString(tr.To) } @@ -694,68 +693,17 @@ func (s *Server) getNEP5Transfers(ps request.Params) (interface{}, *response.Err return bs, nil } -func amountToString(amount *big.Int, decimals int64) string { - if decimals == 0 { - return amount.String() - } - pow := int64(math.Pow10(int(decimals))) - q, r := new(big.Int).DivMod(amount, big.NewInt(pow), new(big.Int)) - if r.Sign() == 0 { - return q.String() - } - fs := fmt.Sprintf("%%d.%%0%dd", decimals) - return fmt.Sprintf(fs, q, r) -} - -// decimals represents decimals value for the contract with the specified scripthash. -type decimals struct { - Hash util.Uint160 - Value int64 -} - -func (s *Server) getDecimals(contractID int32, cache map[int32]decimals) (decimals, error) { +// getHash returns the hash of the contract by its ID using cache. +func (s *Server) getHash(contractID int32, cache map[int32]util.Uint160) (util.Uint160, error) { if d, ok := cache[contractID]; ok { return d, nil } h, err := s.chain.GetContractScriptHash(contractID) if err != nil { - return decimals{}, err + return util.Uint160{}, err } - script, err := request.CreateFunctionInvocationScript(h, request.Params{ - { - Type: request.StringT, - Value: "decimals", - }, - { - Type: request.ArrayT, - Value: []request.Param{}, - }, - }) - if err != nil { - return decimals{}, fmt.Errorf("can't create script: %w", err) - } - res := s.runScriptInVM(script, nil) - if res == nil { - return decimals{}, fmt.Errorf("execution error: no result") - } - if res.State != "HALT" { - return decimals{}, fmt.Errorf("execution error: bad VM state %s due to an error %s", res.State, res.FaultException) - } - if len(res.Stack) == 0 { - return decimals{}, fmt.Errorf("execution error: empty stack") - } - - d := decimals{Hash: h} - bi, err := res.Stack[len(res.Stack)-1].TryInteger() - if err != nil { - return decimals{}, err - } - d.Value = bi.Int64() - if d.Value < 0 { - return d, errors.New("incorrect result: negative result") - } - cache[contractID] = d - return d, nil + cache[contractID] = h + return h, nil } func (s *Server) contractIDFromParam(param *request.Param) (int32, *response.Error) { diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 09d867ba7..249719dfd 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -1246,7 +1246,7 @@ func checkNep5Balances(t *testing.T, e *executor, acc interface{}) { Balances: []result.NEP5Balance{ { Asset: rubles, - Amount: "8.77", + Amount: "877", LastUpdated: 6, }, { @@ -1256,7 +1256,7 @@ func checkNep5Balances(t *testing.T, e *executor, acc interface{}) { }, { Asset: e.chain.UtilityTokenHash(), - Amount: "800.09641770", + Amount: "80009641770", LastUpdated: 7, }}, Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(), @@ -1327,7 +1327,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockDeploy2.Timestamp, Asset: e.chain.UtilityTokenHash(), Address: "", // burn - Amount: amountToString(big.NewInt(txDeploy2.SystemFee+txDeploy2.NetworkFee), 8), + Amount: big.NewInt(txDeploy2.SystemFee + txDeploy2.NetworkFee).String(), Index: 7, TxHash: blockDeploy2.Hash(), }, @@ -1335,7 +1335,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockSendRubles.Timestamp, Asset: rublesHash, Address: testchain.PrivateKeyByID(1).Address(), - Amount: "1.23", + Amount: "123", Index: 6, NotifyIndex: 0, TxHash: txSendRubles.Hash(), @@ -1344,7 +1344,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockSendRubles.Timestamp, Asset: e.chain.UtilityTokenHash(), Address: "", // burn - Amount: amountToString(big.NewInt(txSendRubles.SystemFee+txSendRubles.NetworkFee), 8), + Amount: big.NewInt(txSendRubles.SystemFee + txSendRubles.NetworkFee).String(), Index: 6, TxHash: blockSendRubles.Hash(), }, @@ -1352,7 +1352,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockReceiveRubles.Timestamp, Asset: e.chain.UtilityTokenHash(), Address: "", // burn - Amount: amountToString(big.NewInt(txReceiveRubles.SystemFee+txReceiveRubles.NetworkFee), 8), + Amount: big.NewInt(txReceiveRubles.SystemFee + txReceiveRubles.NetworkFee).String(), Index: 5, TxHash: blockReceiveRubles.Hash(), }, @@ -1360,7 +1360,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockReceiveRubles.Timestamp, Asset: e.chain.UtilityTokenHash(), Address: "", // burn - Amount: amountToString(big.NewInt(txInitCall.SystemFee+txInitCall.NetworkFee), 8), + Amount: big.NewInt(txInitCall.SystemFee + txInitCall.NetworkFee).String(), Index: 5, TxHash: blockReceiveRubles.Hash(), }, @@ -1377,7 +1377,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockSendNEO.Timestamp, Asset: e.chain.UtilityTokenHash(), Address: "", // burn - Amount: amountToString(big.NewInt(txSendNEO.SystemFee+txSendNEO.NetworkFee), 8), + Amount: big.NewInt(txSendNEO.SystemFee + txSendNEO.NetworkFee).String(), Index: 4, TxHash: blockSendNEO.Hash(), }, @@ -1385,7 +1385,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockCtrInv1.Timestamp, Asset: e.chain.UtilityTokenHash(), Address: "", // burn has empty receiver - Amount: amountToString(big.NewInt(txCtrInv1.SystemFee+txCtrInv1.NetworkFee), 8), + Amount: big.NewInt(txCtrInv1.SystemFee + txCtrInv1.NetworkFee).String(), Index: 3, TxHash: blockCtrInv1.Hash(), }, @@ -1393,7 +1393,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockCtrDeploy.Timestamp, Asset: e.chain.UtilityTokenHash(), Address: "", // burn has empty receiver - Amount: amountToString(big.NewInt(txCtrDeploy.SystemFee+txCtrDeploy.NetworkFee), 8), + Amount: big.NewInt(txCtrDeploy.SystemFee + txCtrDeploy.NetworkFee).String(), Index: 2, TxHash: blockCtrDeploy.Hash(), }, @@ -1403,7 +1403,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockGASBounty.Timestamp, Asset: e.chain.UtilityTokenHash(), Address: "", - Amount: "0.50000000", + Amount: "50000000", Index: 6, NotifyIndex: 0, TxHash: blockGASBounty.Hash(), @@ -1412,7 +1412,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockReceiveRubles.Timestamp, Asset: rublesHash, Address: address.Uint160ToString(rublesHash), - Amount: "10", + Amount: "1000", Index: 5, NotifyIndex: 0, TxHash: txReceiveRubles.Hash(), @@ -1421,7 +1421,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockSendNEO.Timestamp, Asset: e.chain.UtilityTokenHash(), Address: "", // Minted GAS. - Amount: "1.49998500", + Amount: "149998500", Index: 4, NotifyIndex: 0, TxHash: txSendNEO.Hash(), @@ -1430,7 +1430,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockReceiveGAS.Timestamp, Asset: e.chain.UtilityTokenHash(), Address: testchain.MultisigAddress(), - Amount: "1000", + Amount: "100000000000", Index: 1, NotifyIndex: 0, TxHash: txReceiveGAS.Hash(), @@ -1448,7 +1448,7 @@ func checkNep5TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcv Timestamp: blockGASBounty0.Timestamp, Asset: e.chain.UtilityTokenHash(), Address: "", - Amount: "0.50000000", + Amount: "50000000", Index: 0, TxHash: blockGASBounty0.Hash(), },