diff --git a/cmd/geth/main.go b/cmd/geth/main.go index d2cccc5a004b..049012464684 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -227,6 +227,9 @@ var ( utils.BlockMinBuildTime, utils.BlockMinBuildTxs, utils.BlockTrailTime, + utils.PublicRequestsCacheLocation, + utils.MaxPublicRequests, + utils.BootnodeCount, } ) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 625e4fbbd167..72c255e1e389 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -22,6 +22,7 @@ import ( "fmt" "math" "math/big" + "math/rand" "os" "path/filepath" godebug "runtime/debug" @@ -1086,6 +1087,21 @@ var ( Value: params.BlockTrailTime, Category: flags.WemixCategory, } + PublicRequestsCacheLocation = &cli.StringFlag{ + Name: "wemix.publicrequests.cache", + Usage: "Public requests cache location", + Value: params.PublicRequestsCacheLocation, + } + MaxPublicRequests = &cli.Int64Flag{ + Name: "wemix.publicrequests.max", + Usage: "Max # of concurrent public requests", + Value: params.MaxPublicRequests, + } + BootnodeCount = &cli.IntFlag{ + Name: "wemix.bootnodecount", + Usage: "Default bootnode peer count", + Value: params.BootnodeCount, + } ) var ( @@ -1172,15 +1188,40 @@ func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) { } } +// setRandomBootstrapNodes setting a random list of bootstrap nodes using the command line +func setRandomBootstrapNodes(ctx *cli.Context, bootnodes []string) []string { + rand.Seed(time.Now().UnixNano()) + bootnodeslen := len(bootnodes) + + // check command line + if ctx.IsSet(BootnodeCount.Name) { + setcount := ctx.Int(BootnodeCount.Name) + if setcount > 0 && setcount <= bootnodeslen { + params.BootnodeCount = setcount + } + } + // select random bootnodes + selectcount := params.BootnodeCount + urls := make([]string, selectcount) + tempnode := make([]string, bootnodeslen) + copy(tempnode, bootnodes) + for i := 0; i < selectcount; i++ { + index := rand.Intn(len(tempnode)) + urls = append(urls, tempnode[index]) + tempnode = append(tempnode[:index], tempnode[index+1:]...) + } + return urls +} + // setBootstrapNodes creates a list of bootstrap nodes from the command line // flags, reverting to pre-configured ones if none have been specified. func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { - urls := params.WemixMainnetBootnodes + urls := setRandomBootstrapNodes(ctx, params.WemixMainnetBootnodes) switch { case ctx.IsSet(BootnodesFlag.Name): urls = SplitAndTrim(ctx.String(BootnodesFlag.Name)) case ctx.Bool(WemixTestnetFlag.Name): - urls = params.WemixTestnetBootnodes + urls = setRandomBootstrapNodes(ctx, params.WemixTestnetBootnodes) case ctx.Bool(RopstenFlag.Name): urls = params.RopstenBootnodes case ctx.Bool(SepoliaFlag.Name): @@ -2152,6 +2193,12 @@ func SetWemixConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { if ctx.IsSet(BlockTrailTime.Name) { params.BlockTrailTime = ctx.Int64(BlockTrailTime.Name) } + if ctx.IsSet(PublicRequestsCacheLocation.Name) { + params.PublicRequestsCacheLocation = ctx.String(PublicRequestsCacheLocation.Name) + } + if ctx.IsSet(MaxPublicRequests.Name) { + params.MaxPublicRequests = ctx.Int64(MaxPublicRequests.Name) + } if params.ConsensusMethod == params.ConsensusInvalid { params.ConsensusMethod = params.ConsensusPoW diff --git a/eth/api.go b/eth/api.go index e0a9c11bb496..6a9a9226f3da 100644 --- a/eth/api.go +++ b/eth/api.go @@ -387,7 +387,7 @@ func (api *DebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) } else { blockRlp = fmt.Sprintf("%#x", rlpBytes) } - if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true, api.eth.APIBackend.ChainConfig()); err != nil { + if blockJSON, err = ethapi.RPCMarshalBlock(ctx, block, true, true, api.eth.APIBackend.ChainConfig()); err != nil { blockJSON = map[string]interface{}{"error": err.Error()} } results = append(results, &BadBlockArgs{ diff --git a/eth/protocols/eth/peer.go b/eth/protocols/eth/peer.go index 500b20d27362..7846a734e534 100644 --- a/eth/protocols/eth/peer.go +++ b/eth/protocols/eth/peer.go @@ -32,7 +32,7 @@ import ( const ( // maxKnownTxs is the maximum transactions hashes to keep in the known list // before starting to randomly evict them. - maxKnownTxs = 2000000 + maxKnownTxs = 100000 // maxKnownBlocks is the maximum block hashes to keep in the known list // before starting to randomly evict them. diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index c672de192e4d..38d14091ba11 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -20,9 +20,12 @@ import ( "context" "errors" "fmt" + "io" "math/big" "os" + "runtime" "strings" + "sync" "time" "github.com/davecgh/go-spew/spew" @@ -42,6 +45,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/vrf" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" @@ -50,6 +54,29 @@ import ( "github.com/tyler-smith/go-bip39" ) +var apiRequestsCache ethdb.Database +var apiRequestsThrottle chan struct{} +var apiRequestsTokens chan struct{} + +func apiRequestsEnter() { + if len(apiRequestsThrottle) >= int(params.MaxPublicRequests) { + pc, _, _, _ := runtime.Caller(1) + var name string + parts := strings.Split(runtime.FuncForPC(pc).Name(), ".") + if len(parts) > 0 { + name = parts[len(parts)-1] + } else { + name = runtime.FuncForPC(pc).Name() + } + log.Warn("Too many API requests", "func", name, "count", len(apiRequestsThrottle)) + } + apiRequestsThrottle <- struct{}{} +} + +func apiRequestsLeave() { + <-apiRequestsThrottle +} + // EthereumAPI provides an API to access Ethereum related information. type EthereumAPI struct { b Backend @@ -674,6 +701,20 @@ type BlockChainAPI struct { // NewBlockChainAPI creates a new Ethereum blockchain API. func NewBlockChainAPI(b Backend) *BlockChainAPI { + if len(params.PublicRequestsCacheLocation) > 0 { + var err error + apiRequestsCache, err = apiCacheOpen(params.PublicRequestsCacheLocation) + if err != nil { + panic(err) + } + } + apiRequestsThrottle = make(chan struct{}, params.MaxPublicRequests) + tokens := runtime.NumCPU() * 8 / 10 + if tokens < 4 { + tokens = 4 + } + apiRequestsTokens = make(chan struct{}, tokens) + return &BlockChainAPI{b} } @@ -695,6 +736,22 @@ func (s *BlockChainAPI) BlockNumber() hexutil.Uint64 { // GetBlockReceipts returns all the transaction receipts for the given block hash. func (s *BlockChainAPI) GetReceiptsByHash(ctx context.Context, blockHash common.Hash) ([]map[string]interface{}, error) { + apiRequestsEnter() + defer apiRequestsLeave() + + select { + case <-ctx.Done(): + return nil, io.EOF + default: + } + + if apiRequestsCache != nil { + if fields, err := apiCacheGetReceipts(apiRequestsCache, blockHash.Bytes()); err == nil { + log.Debug("API Cache", "found receipts", blockHash) + return fields, nil + } + } + block, err1 := s.b.BlockByHash(ctx, blockHash) if block == nil && err1 == nil { return nil, nil @@ -713,54 +770,75 @@ func (s *BlockChainAPI) GetReceiptsByHash(ctx context.Context, blockHash common. if receipts.Len() != txs.Len() { return nil, fmt.Errorf("the size of transactions and receipts is different in the block (%s)", blockHash.String()) } - fieldsList := make([]map[string]interface{}, 0, len(receipts)) + + isLondon := s.b.ChainConfig().IsLondon(new(big.Int).SetUint64(block.NumberU64())) + baseFee := new(big.Int).Set(common.Big0) + if isLondon { + baseFee = block.BaseFee() + } + + fieldsList := make([]map[string]interface{}, len(receipts)) + + var wg sync.WaitGroup for index, receipt := range receipts { - bigblock := new(big.Int).SetUint64(block.NumberU64()) - signer := types.MakeSigner(s.b.ChainConfig(), bigblock) - from, _ := types.Sender(signer, txs[index]) - - fields := map[string]interface{}{ - "blockHash": blockHash, - "blockNumber": hexutil.Uint64(block.NumberU64()), - "transactionHash": receipt.TxHash, - "transactionIndex": hexutil.Uint64(index), - "from": from, - "to": txs[index].To(), - "gasUsed": hexutil.Uint64(receipt.GasUsed), - "cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed), - "contractAddress": nil, - "logs": receipt.Logs, - "logsBloom": receipt.Bloom, - "type": hexutil.Uint(txs[index].Type()), - } - - // Assign the effective gas price paid - if !s.b.ChainConfig().IsLondon(bigblock) { - fields["effectiveGasPrice"] = (*hexutil.Big)(txs[index].GasPrice()) - } else { - header, err := s.b.HeaderByHash(ctx, blockHash) - if err != nil { - return nil, err + wg.Add(1) + go func(i int, txReceipt *types.Receipt, isLondon bool, baseFee *big.Int) { + apiRequestsTokens <- struct{}{} + defer func() { + wg.Done() + <-apiRequestsTokens + }() + select { + case <-ctx.Done(): + return + default: } - gasPrice := new(big.Int).Add(header.BaseFee, txs[index].EffectiveGasTipValue(header.BaseFee)) - fields["effectiveGasPrice"] = (*hexutil.Big)(gasPrice) - } - // Assign receipt status or post state. - if len(receipt.PostState) > 0 { - fields["root"] = hexutil.Bytes(receipt.PostState) - } else { - fields["status"] = hexutil.Uint(receipt.Status) - } - if receipt.Logs == nil { - fields["logs"] = []*types.Log{} - } - // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation - if receipt.ContractAddress != (common.Address{}) { - fields["contractAddress"] = receipt.ContractAddress - } - fieldsList = append(fieldsList, fields) + bigblock := new(big.Int).SetUint64(block.NumberU64()) + signer := types.MakeSigner(s.b.ChainConfig(), bigblock) + from, _ := types.Sender(signer, txs[i]) + fields := map[string]interface{}{ + "blockHash": blockHash, + "blockNumber": hexutil.Uint64(block.NumberU64()), + "transactionHash": txReceipt.TxHash, + "transactionIndex": hexutil.Uint64(i), + "from": from, + "to": txs[i].To(), + "gasUsed": hexutil.Uint64(txReceipt.GasUsed), + "cumulativeGasUsed": hexutil.Uint64(txReceipt.CumulativeGasUsed), + "contractAddress": nil, + "logs": txReceipt.Logs, + "logsBloom": txReceipt.Bloom, + "type": hexutil.Uint(txs[i].Type()), + } + // Assign the effective gas price paid + if !isLondon { + fields["effectiveGasPrice"] = (*hexutil.Big)(txs[i].GasPrice()) + } else { + gasPrice := new(big.Int).Add(baseFee, txs[i].EffectiveGasTipValue(baseFee)) + fields["effectiveGasPrice"] = (*hexutil.Big)(gasPrice) + } + // Assign receipt status or post state. + if len(txReceipt.PostState) > 0 { + fields["root"] = hexutil.Bytes(txReceipt.PostState) + } else { + fields["status"] = hexutil.Uint(txReceipt.Status) + } + if txReceipt.Logs == nil { + fields["logs"] = []*types.Log{} + } + // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation + if txReceipt.ContractAddress != (common.Address{}) { + fields["contractAddress"] = txReceipt.ContractAddress + } + fieldsList[i] = fields + }(index, receipt, isLondon, baseFee) + } + wg.Wait() + + if apiRequestsCache != nil { + apiCachePutReceipts(apiRequestsCache, blockHash.Bytes(), fieldsList) } return fieldsList, nil } @@ -876,6 +954,9 @@ func (s *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) m // - When fullTx is true all transactions in the block are returned, otherwise // only the transaction hash is returned. func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { + apiRequestsEnter() + defer apiRequestsLeave() + block, err := s.b.BlockByNumber(ctx, number) if block != nil && err == nil { response, err := s.rpcMarshalBlock(ctx, block, true, fullTx) @@ -893,6 +974,9 @@ func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNu // GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full // detail, otherwise only the transaction hash is returned. func (s *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { + apiRequestsEnter() + defer apiRequestsLeave() + block, err := s.b.BlockByHash(ctx, hash) if block != nil { return s.rpcMarshalBlock(ctx, block, true, fullTx) @@ -902,6 +986,9 @@ func (s *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fu // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. func (s *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { + apiRequestsEnter() + defer apiRequestsLeave() + block, err := s.b.BlockByNumber(ctx, blockNr) if block != nil { uncles := block.Uncles() @@ -917,6 +1004,9 @@ func (s *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, block // GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. func (s *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) { + apiRequestsEnter() + defer apiRequestsLeave() + block, err := s.b.BlockByHash(ctx, blockHash) if block != nil { uncles := block.Uncles() @@ -932,6 +1022,9 @@ func (s *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHa // GetUncleCountByBlockNumber returns number of uncles in the block for the given block number func (s *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { + apiRequestsEnter() + defer apiRequestsLeave() + if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { n := hexutil.Uint(len(block.Uncles())) return &n @@ -941,6 +1034,9 @@ func (s *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr // GetUncleCountByBlockHash returns number of uncles in the block for the given block hash func (s *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { + apiRequestsEnter() + defer apiRequestsLeave() + if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { n := hexutil.Uint(len(block.Uncles())) return &n @@ -1330,7 +1426,20 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { // RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // transaction hashes. -func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig) (map[string]interface{}, error) { +func RPCMarshalBlock(ctx context.Context, block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig) (map[string]interface{}, error) { + select { + case <-ctx.Done(): + return nil, io.EOF + default: + } + + if fullTx && apiRequestsCache != nil { + if fields, err := apiCacheGetBlock(apiRequestsCache, block.Hash().Bytes()); err == nil { + log.Debug("API Cache", "found block", block.Number()) + return fields, nil + } + } + fields := RPCMarshalHeader(block.Header()) fields["size"] = hexutil.Uint64(block.Size()) @@ -1345,11 +1454,33 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param } txs := block.Transactions() transactions := make([]interface{}, len(txs)) + var wg sync.WaitGroup var err error for i, tx := range txs { - if transactions[i], err = formatTx(tx); err != nil { - return nil, err - } + wg.Add(1) + go func(ii int, itx *types.Transaction) { + apiRequestsTokens <- struct{}{} + defer func() { + wg.Done() + <-apiRequestsTokens + }() + + select { + case <-ctx.Done(): + err = io.EOF + return + default: + } + var err2 error + transactions[ii], err2 = formatTx(itx) + if err2 != nil { + err = err2 + } + }(i, tx) + } + wg.Wait() + if err != nil { + return nil, err } fields["transactions"] = transactions } @@ -1360,6 +1491,10 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param } fields["uncles"] = uncleHashes + if fullTx && apiRequestsCache != nil { + apiCachePutBlock(apiRequestsCache, block.Hash().Bytes(), fields) + } + return fields, nil } @@ -1374,7 +1509,7 @@ func (s *BlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Head // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires // a `BlockchainAPI`. func (s *BlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { - fields, err := RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig()) + fields, err := RPCMarshalBlock(ctx, b, inclTx, fullTx, s.b.ChainConfig()) if err != nil { return nil, err } diff --git a/internal/ethapi/api_cache.go b/internal/ethapi/api_cache.go new file mode 100644 index 000000000000..fd950a999923 --- /dev/null +++ b/internal/ethapi/api_cache.go @@ -0,0 +1,126 @@ +// Copyright 2023 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package ethapi + +import ( + "bytes" + "compress/gzip" + "encoding/json" + "io" + + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/ethdb" +) + +var marshaledBlockPrefix = []byte(".blck.") +var marshaledReceiptsPrefix = []byte(".rcpt.") + +func apiCacheOpen(fn string) (ethdb.Database, error) { + return rawdb.NewDB(fn, 0, 0, "", false) +} + +func apiCacheClose(db ethdb.Database) { + db.Close() +} + +func apiCacheGet(db ethdb.Database, prefix, hash []byte) ([]byte, error) { + key := append(prefix, hash...) + data, err := db.Get(key) + if err != nil { + return nil, err + } + + gzReader, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + defer gzReader.Close() + + decompressedData, err := io.ReadAll(gzReader) + if err != nil { + return nil, err + } + return decompressedData, nil +} + +func apiCacheHas(db ethdb.Database, prefix, hash []byte) (bool, error) { + key := append(prefix, hash...) + return db.Has(key) +} + +func apiCachePut(db ethdb.Database, prefix, hash, data []byte) error { + var buf bytes.Buffer + gzWriter := gzip.NewWriter(&buf) + if _, err := gzWriter.Write(data); err != nil { + return err + } + if err := gzWriter.Close(); err != nil { + return err + } + + key := append(prefix, hash...) + return db.Put(key, buf.Bytes()) +} + +func apiCacheDelete(db ethdb.Database, prefix, hash []byte) error { + key := append(prefix, hash...) + return db.Delete(key) +} + +func apiCacheGetBlock(db ethdb.Database, hash []byte) (map[string]interface{}, error) { + data, err := apiCacheGet(db, marshaledBlockPrefix, hash) + if err != nil { + return nil, err + } + + var fields map[string]interface{} + if err = json.Unmarshal(data, &fields); err != nil { + return nil, err + } + return fields, nil +} + +func apiCachePutBlock(db ethdb.Database, hash []byte, fields map[string]interface{}) error { + data, err := json.Marshal(fields) + if err != nil { + return err + } + return apiCachePut(db, marshaledBlockPrefix, hash, data) +} + +func apiCacheGetReceipts(db ethdb.Database, hash []byte) ([]map[string]interface{}, error) { + data, err := apiCacheGet(db, marshaledReceiptsPrefix, hash) + if err != nil { + return nil, err + } + + var fields []map[string]interface{} + if err = json.Unmarshal(data, &fields); err != nil { + return nil, err + } + return fields, nil +} + +func apiCachePutReceipts(db ethdb.Database, hash []byte, fields []map[string]interface{}) error { + data, err := json.Marshal(fields) + if err != nil { + return err + } + return apiCachePut(db, marshaledReceiptsPrefix, hash, data) +} + +// EoF diff --git a/node/rpcstack.go b/node/rpcstack.go index 5d411fa61e81..8244c892ff50 100644 --- a/node/rpcstack.go +++ b/node/rpcstack.go @@ -267,13 +267,15 @@ func (h *httpServer) doStop() { h.wsHandler.Store((*rpcHandler)(nil)) wsHandler.server.Stop() } + ctx, cancel := context.WithTimeout(context.Background(), shutdownTimeout) defer cancel() err := h.server.Shutdown(ctx) - if err == ctx.Err() { + if err != nil && err == ctx.Err() { h.log.Warn("HTTP server graceful shutdown timed out") h.server.Close() } + h.listener.Close() h.log.Info("HTTP server stopped", "endpoint", h.listener.Addr()) diff --git a/p2p/peer.go b/p2p/peer.go index 469a1b797416..f3d5a0f24c2f 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -112,6 +112,7 @@ type Peer struct { wg sync.WaitGroup protoErr chan error closed chan struct{} + pingRecv chan struct{} disc chan DiscReason // events receives message send / receive events if set @@ -233,6 +234,7 @@ func newPeer(log log.Logger, conn *conn, protocols []Protocol) *Peer { disc: make(chan DiscReason), protoErr: make(chan error, len(protomap)+1), // protocols + pingLoop closed: make(chan struct{}), + pingRecv: make(chan struct{}, 16), log: log.New("id", conn.node.ID(), "conn", conn.flags), } return p @@ -293,9 +295,11 @@ loop: } func (p *Peer) pingLoop() { - ping := time.NewTimer(pingInterval) defer p.wg.Done() + + ping := time.NewTimer(pingInterval) defer ping.Stop() + for { select { case <-ping.C: @@ -304,6 +308,10 @@ func (p *Peer) pingLoop() { return } ping.Reset(pingInterval) + + case <-p.pingRecv: + SendItems(p.rw, pongMsg) + case <-p.closed: return } @@ -330,7 +338,10 @@ func (p *Peer) handle(msg Msg) error { switch { case msg.Code == pingMsg: msg.Discard() - go SendItems(p.rw, pongMsg) + select { + case p.pingRecv <- struct{}{}: + case <-p.closed: + } case msg.Code == discMsg: // This is the last message. We don't need to discard or // check errors because, the connection will be closed after it. diff --git a/params/protocol_params.go b/params/protocol_params.go index b64e82ba54d8..86623d79d990 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -202,4 +202,8 @@ var ( BlockMinBuildTime int64 = 300 // Minimum block generation time in ms BlockMinBuildTxs int64 = 2500 // Minimum txs in a block with pending txs BlockTrailTime int64 = 300 // Time to leave for block data transfer transfer in ms + + PublicRequestsCacheLocation string = "" // Cache DB location + MaxPublicRequests int64 = 100 // Max # of concurrent public requests + BootnodeCount int = 3 // Default bootnode peer count. ) diff --git a/params/version.go b/params/version.go index fe5e96fcb700..65bce5efb03b 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 0 // Major version component of the current release VersionMinor = 10 // Minor version component of the current release - VersionPatch = 6 // Patch version component of the current release + VersionPatch = 7 // Patch version component of the current release VersionMeta = "stable" // Version metadata to append to the version string )