diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index c5d88068c..ec9d14f57 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1237,10 +1237,10 @@ func (bc *Blockchain) headerListLen() (n int) { 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) { 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) } diff --git a/pkg/rpc/response/result/tx_raw_output.go b/pkg/rpc/response/result/tx_raw_output.go index 3f1727f30..6b2035944 100644 --- a/pkg/rpc/response/result/tx_raw_output.go +++ b/pkg/rpc/response/result/tx_raw_output.go @@ -28,29 +28,27 @@ type TransactionMetadata struct { // NewTransactionOutputRaw returns a new ransactionOutputRaw object. func NewTransactionOutputRaw(tx *transaction.Transaction, header *block.Header, chain core.Blockchainer) TransactionOutputRaw { - // confirmations formula - confirmations := int(chain.BlockHeight() - header.Base.Index + 1) - return TransactionOutputRaw{ + result := TransactionOutputRaw{ Transaction: tx, TransactionMetadata: TransactionMetadata{ - SysFee: chain.SystemFee(tx), - NetFee: chain.NetworkFee(tx), - Blockhash: header.Hash(), - Confirmations: confirmations, - Timestamp: header.Timestamp, + SysFee: chain.SystemFee(tx), + NetFee: chain.NetworkFee(tx), }, } + 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. func (t TransactionOutputRaw) MarshalJSON() ([]byte, error) { - output, err := json.Marshal(TransactionMetadata{ - SysFee: t.SysFee, - NetFee: t.NetFee, - Blockhash: t.Blockhash, - Confirmations: t.Confirmations, - Timestamp: t.Timestamp, - }) + output, err := json.Marshal(t.TransactionMetadata) if err != nil { return nil, err } @@ -78,17 +76,6 @@ func (t *TransactionOutputRaw) UnmarshalJSON(data []byte) error { if err != nil { return err } - t.SysFee = output.SysFee - t.NetFee = output.NetFee - 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 + t.TransactionMetadata = *output + return json.Unmarshal(data, &t.Transaction) } diff --git a/pkg/rpc/response/result/unclaimed.go b/pkg/rpc/response/result/unclaimed.go index e636f5c1a..54ea4e94d 100644 --- a/pkg/rpc/response/result/unclaimed.go +++ b/pkg/rpc/response/result/unclaimed.go @@ -1,6 +1,9 @@ package result import ( + "errors" + "math" + "github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core/state" "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 { 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) if err != nil { return nil, err diff --git a/pkg/rpc/server/server.go b/pkg/rpc/server/server.go index 6eabd408d..f79bf7694 100644 --- a/pkg/rpc/server/server.go +++ b/pkg/rpc/server/server.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "math" "net" "net/http" "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) { - var resultsErr *response.Error - var results interface{} - - if txHash, err := reqParams.Value(0).GetUint256(); err != nil { - resultsErr = response.ErrInvalidParams - } else if tx, height, err := s.chain.GetTransaction(txHash); err != nil { + txHash, err := reqParams.Value(0).GetUint256() + if err != nil { + return nil, response.ErrInvalidParams + } + tx, height, err := s.chain.GetTransaction(txHash) + if err != nil { err = errors.Wrapf(err, "Invalid transaction hash: %s", txHash) 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, err := s.chain.GetHeader(_header) if err != nil { - resultsErr = response.NewInvalidParamsError(err.Error(), err) - } else { - results = result.NewTransactionOutputRaw(tx, header, s.chain) + return nil, response.NewInvalidParamsError(err.Error(), err) } - } 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) { @@ -1189,7 +1192,7 @@ func (s *Server) getTransactionHeight(ps request.Params) (interface{}, *response } _, height, err := s.chain.GetTransaction(h) - if err != nil { + if err != nil || height == math.MaxUint32 { return nil, response.NewRPCError("unknown transaction", "", nil) }