Merge pull request #1648 from nspcc-dev/backport-fixes-from-master

Backport fixes from master to 2.x
This commit is contained in:
Roman Khimov 2021-01-11 12:44:05 +03:00 committed by GitHub
commit 89fb02a7f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 112 additions and 64 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

@ -248,9 +248,6 @@ func (m *Message) Bytes() ([]byte, error) {
if err := m.Encode(w.BinWriter); err != nil { if err := m.Encode(w.BinWriter); err != nil {
return nil, err return nil, err
} }
if w.Err != nil {
return nil, w.Err
}
return w.Bytes(), nil return w.Bytes(), nil
} }

View file

@ -266,7 +266,28 @@ func (s *Server) run() {
addr := drop.peer.PeerAddr().String() addr := drop.peer.PeerAddr().String()
if drop.reason == errIdenticalID { if drop.reason == errIdenticalID {
s.discovery.RegisterBadAddr(addr) s.discovery.RegisterBadAddr(addr)
} else if drop.reason != errAlreadyConnected { } else if drop.reason == errAlreadyConnected {
// There is a race condition when peer can be disconnected twice for the this reason
// which can lead to no connections to peer at all. Here we check for such a possibility.
stillConnected := false
s.lock.RLock()
verDrop := drop.peer.Version()
addr := drop.peer.PeerAddr().String()
if verDrop != nil {
for peer := range s.peers {
ver := peer.Version()
// Already connected, drop this connection.
if ver != nil && ver.Nonce == verDrop.Nonce && peer.PeerAddr().String() == addr {
stillConnected = true
}
}
}
s.lock.RUnlock()
if !stillConnected {
s.discovery.UnregisterConnectedAddr(addr)
s.discovery.BackFill(addr)
}
} else {
s.discovery.UnregisterConnectedAddr(addr) s.discovery.UnregisterConnectedAddr(addr)
s.discovery.BackFill(addr) s.discovery.BackFill(addr)
} }
@ -866,11 +887,21 @@ func (s *Server) requestTx(hashes ...util.Uint256) {
return return
} }
msg := s.MkMsg(CMDGetData, payload.NewInventory(payload.TXType, hashes)) for i := 0; i <= len(hashes)/payload.MaxHashesCount; i++ {
start := i * payload.MaxHashesCount
stop := (i + 1) * payload.MaxHashesCount
if stop > len(hashes) {
stop = len(hashes)
}
if start == stop {
break
}
msg := s.MkMsg(CMDGetData, payload.NewInventory(payload.TXType, hashes[start:stop]))
// It's high priority because it directly affects consensus process, // It's high priority because it directly affects consensus process,
// even though it's getdata. // even though it's getdata.
s.broadcastHPMessage(msg) s.broadcastHPMessage(msg)
} }
}
// iteratePeersWithSendMsg sends given message to all peers using two functions // iteratePeersWithSendMsg sends given message to all peers using two functions
// passed, one is to send the message and the other is to filtrate peers (the // passed, one is to send the message and the other is to filtrate peers (the

View file

@ -178,6 +178,7 @@ func (p *TCPPeer) handleQueues() {
var p2pSkipCounter uint32 var p2pSkipCounter uint32
const p2pSkipDivisor = 4 const p2pSkipDivisor = 4
var writeTimeout = time.Duration(p.server.chain.GetConfig().SecondsPerBlock) * time.Second
for { for {
var msg []byte var msg []byte
@ -211,6 +212,10 @@ func (p *TCPPeer) handleQueues() {
case msg = <-p.sendQ: case msg = <-p.sendQ:
} }
} }
err = p.conn.SetWriteDeadline(time.Now().Add(writeTimeout))
if err != nil {
break
}
_, err = p.conn.Write(msg) _, err = p.conn.Write(msg)
if err != nil { if err != nil {
break break

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)
} }

View file

@ -213,8 +213,13 @@ func handleIP(c *ishell.Context) {
return return
} }
v := getVMFromContext(c) v := getVMFromContext(c)
ip, opcode := v.Context().CurrInstr() ctx := v.Context()
if ctx.NextIP() < ctx.LenInstr() {
ip, opcode := v.Context().NextInstr()
c.Printf("instruction pointer at %d (%s)\n", ip, opcode) c.Printf("instruction pointer at %d (%s)\n", ip, opcode)
} else {
c.Println("execution has finished")
}
} }
func handleBreak(c *ishell.Context) { func handleBreak(c *ishell.Context) {
@ -224,6 +229,7 @@ func handleBreak(c *ishell.Context) {
v := getVMFromContext(c) v := getVMFromContext(c)
if len(c.Args) != 1 { if len(c.Args) != 1 {
c.Err(errors.New("missing parameter <ip>")) c.Err(errors.New("missing parameter <ip>"))
return
} }
n, err := strconv.Atoi(c.Args[0]) n, err := strconv.Atoi(c.Args[0])
if err != nil { if err != nil {
@ -319,7 +325,6 @@ func runVMWithHandling(c *ishell.Context, v *vm.VM) {
err := v.Run() err := v.Run()
if err != nil { if err != nil {
c.Err(err) c.Err(err)
return
} }
checkAndPrintVMState(c, v) checkAndPrintVMState(c, v)
} }
@ -331,16 +336,20 @@ func checkAndPrintVMState(c *ishell.Context, v *vm.VM) {
var message string var message string
switch { switch {
case v.HasFailed(): case v.HasFailed():
message = "FAILED" message = "" // the error will be printed on return
case v.HasHalted(): case v.HasHalted():
message = v.Stack("estack") message = v.Stack("estack")
case v.AtBreakpoint(): case v.AtBreakpoint():
ctx := v.Context() ctx := v.Context()
i, op := ctx.CurrInstr() if ctx.NextIP() < ctx.LenInstr() {
message = fmt.Sprintf("at breakpoint %d (%s)\n", i, op.String()) i, op := ctx.NextInstr()
message = fmt.Sprintf("at breakpoint %d (%s)", i, op)
} else {
message = "execution has finished"
}
} }
if message != "" { if message != "" {
c.Printf(message) c.Println(message)
} }
} }
@ -412,8 +421,9 @@ func handleStepType(c *ishell.Context, stepType string) {
} }
if err != nil { if err != nil {
c.Err(err) c.Err(err)
} } else {
handleIP(c) handleIP(c)
}
changePrompt(c, v) changePrompt(c, v)
} }
@ -426,8 +436,8 @@ func handleOps(c *ishell.Context) {
} }
func changePrompt(c ishell.Actions, v *vm.VM) { func changePrompt(c ishell.Actions, v *vm.VM) {
if v.Ready() && v.Context().IP()-1 >= 0 { if v.Ready() && v.Context().NextIP() >= 0 && v.Context().NextIP() < v.Context().LenInstr() {
c.SetPrompt(fmt.Sprintf("NEO-GO-VM %d > ", v.Context().IP()-1)) c.SetPrompt(fmt.Sprintf("NEO-GO-VM %d > ", v.Context().NextIP()))
} else { } else {
c.SetPrompt("NEO-GO-VM > ") c.SetPrompt("NEO-GO-VM > ")
} }

View file

@ -143,6 +143,15 @@ func (c *Context) CurrInstr() (int, opcode.Opcode) {
return c.ip, opcode.Opcode(c.prog[c.ip]) return c.ip, opcode.Opcode(c.prog[c.ip])
} }
// NextInstr returns the next instruction and opcode.
func (c *Context) NextInstr() (int, opcode.Opcode) {
op := opcode.RET
if c.nextip < len(c.prog) {
op = opcode.Opcode(c.prog[c.nextip])
}
return c.nextip, op
}
// Copy returns an new exact copy of c. // Copy returns an new exact copy of c.
func (c *Context) Copy() *Context { func (c *Context) Copy() *Context {
ctx := new(Context) ctx := new(Context)

View file

@ -228,7 +228,7 @@ func (v *VM) AddBreakPoint(n int) {
// instruction pointer. // instruction pointer.
func (v *VM) AddBreakPointRel(n int) { func (v *VM) AddBreakPointRel(n int) {
ctx := v.Context() ctx := v.Context()
v.AddBreakPoint(ctx.ip + n) v.AddBreakPoint(ctx.nextip + n)
} }
// LoadFile loads a program from the given path, ready to execute it. // LoadFile loads a program from the given path, ready to execute it.