rpc: adjust getrawtransaction and gettransactionheight RPC call

We should not return transaction metadata from `getrawtransaction` in case
transaction is not in the mempool. Height shouldn't be returned from
`gettransactionheight` in case transaction is in the mempool.
This commit is contained in:
Anna Shaleva 2020-11-13 16:54:38 +03:00 committed by Roman Khimov
parent 124c674b17
commit 4a8259caea
4 changed files with 41 additions and 45 deletions

View file

@ -1237,10 +1237,10 @@ func (bc *Blockchain) headerListLen() (n int) {
return return
} }
// GetTransaction returns a TX and its height by the given hash. // GetTransaction returns a TX and its height by the given hash. The height is MaxUint32 if tx is in the mempool.
func (bc *Blockchain) GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error) { func (bc *Blockchain) GetTransaction(hash util.Uint256) (*transaction.Transaction, uint32, error) {
if tx, _, ok := bc.memPool.TryGetValue(hash); ok { if tx, _, ok := bc.memPool.TryGetValue(hash); ok {
return tx, 0, nil // the height is not actually defined for memPool transaction. Not sure if zero is a good number in this case. return tx, math.MaxUint32, nil // the height is not actually defined for memPool transaction.
} }
return bc.dao.GetTransaction(hash) return bc.dao.GetTransaction(hash)
} }

View file

@ -28,29 +28,27 @@ type TransactionMetadata struct {
// NewTransactionOutputRaw returns a new ransactionOutputRaw object. // NewTransactionOutputRaw returns a new ransactionOutputRaw object.
func NewTransactionOutputRaw(tx *transaction.Transaction, header *block.Header, chain core.Blockchainer) TransactionOutputRaw { func NewTransactionOutputRaw(tx *transaction.Transaction, header *block.Header, chain core.Blockchainer) TransactionOutputRaw {
// confirmations formula result := TransactionOutputRaw{
confirmations := int(chain.BlockHeight() - header.Base.Index + 1)
return TransactionOutputRaw{
Transaction: tx, Transaction: tx,
TransactionMetadata: TransactionMetadata{ TransactionMetadata: TransactionMetadata{
SysFee: chain.SystemFee(tx), SysFee: chain.SystemFee(tx),
NetFee: chain.NetworkFee(tx), NetFee: chain.NetworkFee(tx),
Blockhash: header.Hash(),
Confirmations: confirmations,
Timestamp: header.Timestamp,
}, },
} }
if header == nil {
return result
}
// confirmations formula
confirmations := int(chain.BlockHeight() - header.Base.Index + 1)
result.TransactionMetadata.Blockhash = header.Hash()
result.TransactionMetadata.Confirmations = confirmations
result.TransactionMetadata.Timestamp = header.Timestamp
return result
} }
// MarshalJSON implements json.Marshaler interface. // MarshalJSON implements json.Marshaler interface.
func (t TransactionOutputRaw) MarshalJSON() ([]byte, error) { func (t TransactionOutputRaw) MarshalJSON() ([]byte, error) {
output, err := json.Marshal(TransactionMetadata{ output, err := json.Marshal(t.TransactionMetadata)
SysFee: t.SysFee,
NetFee: t.NetFee,
Blockhash: t.Blockhash,
Confirmations: t.Confirmations,
Timestamp: t.Timestamp,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -78,17 +76,6 @@ func (t *TransactionOutputRaw) UnmarshalJSON(data []byte) error {
if err != nil { if err != nil {
return err return err
} }
t.SysFee = output.SysFee t.TransactionMetadata = *output
t.NetFee = output.NetFee return json.Unmarshal(data, &t.Transaction)
t.Blockhash = output.Blockhash
t.Confirmations = output.Confirmations
t.Timestamp = output.Timestamp
transaction := new(transaction.Transaction)
err = json.Unmarshal(data, transaction)
if err != nil {
return err
}
t.Transaction = transaction
return nil
} }

View file

@ -1,6 +1,9 @@
package result package result
import ( import (
"errors"
"math"
"github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
@ -38,6 +41,9 @@ func NewUnclaimed(a *state.Account, chain core.Blockchainer) (*Unclaimed, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if txHeight == math.MaxUint32 {
return nil, errors.New("wrong transaction stored in account data")
}
gen, sys, err := chain.CalculateClaimable(usb.Value, txHeight, blockHeight) gen, sys, err := chain.CalculateClaimable(usb.Value, txHeight, blockHeight)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -5,6 +5,7 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"math"
"net" "net"
"net/http" "net/http"
"strconv" "strconv"
@ -1159,27 +1160,29 @@ func (s *Server) getStorage(ps request.Params) (interface{}, *response.Error) {
} }
func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *response.Error) { func (s *Server) getrawtransaction(reqParams request.Params) (interface{}, *response.Error) {
var resultsErr *response.Error txHash, err := reqParams.Value(0).GetUint256()
var results interface{} if err != nil {
return nil, response.ErrInvalidParams
if txHash, err := reqParams.Value(0).GetUint256(); err != nil { }
resultsErr = response.ErrInvalidParams tx, height, err := s.chain.GetTransaction(txHash)
} else if tx, height, err := s.chain.GetTransaction(txHash); err != nil { if err != nil {
err = errors.Wrapf(err, "Invalid transaction hash: %s", txHash) err = errors.Wrapf(err, "Invalid transaction hash: %s", txHash)
return nil, response.NewRPCError("Unknown transaction", err.Error(), err) return nil, response.NewRPCError("Unknown transaction", err.Error(), err)
} else if reqParams.Value(1).GetBoolean() { }
if reqParams.Value(1).GetBoolean() {
if height == math.MaxUint32 {
return result.NewTransactionOutputRaw(tx, nil, s.chain), nil
}
_header := s.chain.GetHeaderHash(int(height)) _header := s.chain.GetHeaderHash(int(height))
header, err := s.chain.GetHeader(_header) header, err := s.chain.GetHeader(_header)
if err != nil { if err != nil {
resultsErr = response.NewInvalidParamsError(err.Error(), err) return nil, response.NewInvalidParamsError(err.Error(), err)
} else {
results = result.NewTransactionOutputRaw(tx, header, s.chain)
}
} else {
results = hex.EncodeToString(tx.Bytes())
} }
return result.NewTransactionOutputRaw(tx, header, s.chain), nil
}
return hex.EncodeToString(tx.Bytes()), nil
return results, resultsErr
} }
func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response.Error) { func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response.Error) {
@ -1189,7 +1192,7 @@ func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response
} }
_, height, err := s.chain.GetTransaction(h) _, height, err := s.chain.GetTransaction(h)
if err != nil { if err != nil || height == math.MaxUint32 {
return nil, response.NewRPCError("unknown transaction", "", nil) return nil, response.NewRPCError("unknown transaction", "", nil)
} }