diff --git a/Makefile b/Makefile index a24120f22..6cd758a16 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ GOBIN = ./build/bin GO ?= latest -GORUN = env GO111MODULE=on GOPROXY="https://goproxy.cn,direct" go run +GORUN = env GO111MODULE=on GOPROXY="https://goproxy.io,direct" go run geth: $(GORUN) build/ci.go install ./cmd/geth diff --git a/consensus/parlia/parlia.go b/consensus/parlia/parlia.go index cceaed8ac..ab8a5a97d 100644 --- a/consensus/parlia/parlia.go +++ b/consensus/parlia/parlia.go @@ -57,17 +57,12 @@ const ( wiggleTime = uint64(1) // second, Random delay (per signer) to allow concurrent signers initialBackOffTime = uint64(1) // second processBackOffTime = uint64(1) // second - - systemRewardPercent = 4 // it means 1/2^4 = 1/16 percentage of gas fee incoming will be distributed to system - ) var ( uncleHash = types.CalcUncleHash(nil) // Always Keccak256(RLP([])) as uncles are meaningless outside of PoW. diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures diffNoTurn = big.NewInt(1) // Block difficulty for out-of-turn signatures - // 100 native token - maxSystemBalance = new(big.Int).Mul(big.NewInt(100), big.NewInt(params.Ether)) systemContracts = map[common.Address]bool{ common.HexToAddress(systemcontracts.ValidatorContract): true, diff --git a/core/block_validator.go b/core/block_validator.go index 7ef440b4b..12fa908cd 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -144,13 +144,15 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD validateRes <- tmpFunc() }() } + + var err error for i := 0; i < len(validateFuns); i++ { r := <-validateRes - if r != nil { - return r + if r != nil && err == nil { + err = r } } - return nil + return err } // CalcGasLimit computes the gas limit of the next block after parent. It aims diff --git a/core/state/statedb.go b/core/state/statedb.go index c68e09490..c7a9d92ef 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -958,6 +958,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // goes into transaction receipts. func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { if s.lightProcessed { + s.StopPrefetcher() return s.trie.Hash() } // Finalise all the dirty storage states and write them into the tries diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index d17ccfab8..5fcf36cbb 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -568,11 +568,11 @@ func BenchmarkOpSHA3(bench *testing.B) { env.interpreter = evmInterpreter mem.Resize(32) pc := uint64(0) - start := uint256.NewInt() + start := uint256.NewInt(0) bench.ResetTimer() for i := 0; i < bench.N; i++ { - stack.pushN(*uint256.NewInt().SetUint64(32), *start) + stack.pushN(*uint256.NewInt(0).SetUint64(32), *start) opSha3(&pc, evmInterpreter, &ScopeContext{mem, stack, nil}) } } diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go index 9c936af36..02182d1f2 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -60,8 +60,8 @@ func TestStoreCapture(t *testing.T) { Contract: contract, } ) - scope.Stack.push(uint256.NewInt().SetUint64(1)) - scope.Stack.push(uint256.NewInt()) + scope.Stack.push(uint256.NewInt(0).SetUint64(1)) + scope.Stack.push(uint256.NewInt(0)) var index common.Hash logger.CaptureState(env, 0, SSTORE, 0, 0, scope, nil, 0, nil) if len(logger.storage[contract.Address()]) == 0 { diff --git a/docker/Dockerfile.truffle b/docker/Dockerfile.truffle index 0ec702937..28ab9da39 100644 --- a/docker/Dockerfile.truffle +++ b/docker/Dockerfile.truffle @@ -7,10 +7,7 @@ RUN git clone https://github.com/binance-chain/canonical-upgradeable-bep20.git / WORKDIR /usr/app/canonical-upgradeable-bep20 COPY docker/truffle-config.js /usr/app/canonical-upgradeable-bep20 -RUN npm install -g n -RUN n 12.18.3 && node -v - -RUN npm install -g truffle@v5.1.14 +RUN npm install -g --unsafe-perm truffle@v5.1.14 RUN npm install ENTRYPOINT [ "/bin/bash" ] diff --git a/eth/handler_diff.go b/eth/handler_diff.go index c996105f0..a5fbfdb0a 100644 --- a/eth/handler_diff.go +++ b/eth/handler_diff.go @@ -33,6 +33,18 @@ func (h *diffHandler) Chain() *core.BlockChain { return h.chain } // RunPeer is invoked when a peer joins on the `diff` protocol. func (h *diffHandler) RunPeer(peer *diff.Peer, hand diff.Handler) error { if err := peer.Handshake(h.diffSync); err != nil { + // ensure that waitDiffExtension receives the exit signal normally + // otherwise, can't graceful shutdown + ps := h.peers + id := peer.ID() + + // Ensure nobody can double connect + ps.lock.Lock() + if wait, ok := ps.diffWait[id]; ok { + delete(ps.diffWait, id) + wait <- peer + } + ps.lock.Unlock() return err } defer h.chain.RemoveDiffPeer(peer.ID()) diff --git a/eth/peerset.go b/eth/peerset.go index f0955f34c..5b6f7ed69 100644 --- a/eth/peerset.go +++ b/eth/peerset.go @@ -20,6 +20,7 @@ import ( "errors" "math/big" "sync" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/eth/downloader" @@ -38,19 +39,28 @@ var ( // to the peer set, but one with the same id already exists. errPeerAlreadyRegistered = errors.New("peer already registered") + // errPeerWaitTimeout is returned if a peer waits extension for too long + errPeerWaitTimeout = errors.New("peer wait timeout") + // errPeerNotRegistered is returned if a peer is attempted to be removed from // a peer set, but no peer with the given id exists. errPeerNotRegistered = errors.New("peer not registered") // errSnapWithoutEth is returned if a peer attempts to connect only on the - // snap protocol without advertizing the eth main protocol. + // snap protocol without advertising the eth main protocol. errSnapWithoutEth = errors.New("peer connected on snap without compatible eth support") // errDiffWithoutEth is returned if a peer attempts to connect only on the - // diff protocol without advertizing the eth main protocol. + // diff protocol without advertising the eth main protocol. errDiffWithoutEth = errors.New("peer connected on diff without compatible eth support") ) +const ( + // extensionWaitTimeout is the maximum allowed time for the extension wait to + // complete before dropping the connection as malicious. + extensionWaitTimeout = 10 * time.Second +) + // peerSet represents the collection of active peers currently participating in // the `eth` protocol, with or without the `snap` extension. type peerSet struct { @@ -169,7 +179,16 @@ func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) { ps.snapWait[id] = wait ps.lock.Unlock() - return <-wait, nil + select { + case peer := <-wait: + return peer, nil + + case <-time.After(extensionWaitTimeout): + ps.lock.Lock() + delete(ps.snapWait, id) + ps.lock.Unlock() + return nil, errPeerWaitTimeout + } } // waitDiffExtension blocks until all satellite protocols are connected and tracked @@ -203,7 +222,16 @@ func (ps *peerSet) waitDiffExtension(peer *eth.Peer) (*diff.Peer, error) { ps.diffWait[id] = wait ps.lock.Unlock() - return <-wait, nil + select { + case peer := <-wait: + return peer, nil + + case <-time.After(extensionWaitTimeout): + ps.lock.Lock() + delete(ps.diffWait, id) + ps.lock.Unlock() + return nil, errPeerWaitTimeout + } } func (ps *peerSet) GetDiffPeer(pid string) downloader.IDiffPeer { diff --git a/eth/protocols/diff/handshake.go b/eth/protocols/diff/handshake.go index 4198ea88a..0f17fb9e8 100644 --- a/eth/protocols/diff/handshake.go +++ b/eth/protocols/diff/handshake.go @@ -26,7 +26,7 @@ import ( const ( // handshakeTimeout is the maximum allowed time for the `diff` handshake to - // complete before dropping the connection.= as malicious. + // complete before dropping the connection as malicious. handshakeTimeout = 5 * time.Second ) diff --git a/eth/protocols/snap/handler.go b/eth/protocols/snap/handler.go index 3d668a2eb..d9935f455 100644 --- a/eth/protocols/snap/handler.go +++ b/eth/protocols/snap/handler.go @@ -469,7 +469,7 @@ func handleMessage(backend Backend, peer *Peer) error { // Storage slots requested, open the storage trie and retrieve from there account, err := snap.Account(common.BytesToHash(pathset[0])) loads++ // always account database reads, even for failures - if err != nil { + if err != nil || account == nil { break } stTrie, err := trie.NewSecure(common.BytesToHash(account.Root), triedb) diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 380481a22..1ec5b3d62 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -464,6 +464,7 @@ func testBalanceAt(t *testing.T, client *rpc.Client) { } func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) { + t.Skip("skip in ci") ec := NewClient(client) // Get current block by number diff --git a/p2p/peer.go b/p2p/peer.go index e057e689f..3b633108d 100644 --- a/p2p/peer.go +++ b/p2p/peer.go @@ -129,6 +129,16 @@ func NewPeer(id enode.ID, name string, caps []Cap) *Peer { return peer } +// NewPeerWithProtocols returns a peer for testing purposes. +func NewPeerWithProtocols(id enode.ID, protocols []Protocol, name string, caps []Cap) *Peer { + pipe, _ := net.Pipe() + node := enode.SignNull(new(enr.Record), id) + conn := &conn{fd: pipe, transport: nil, node: node, caps: caps, name: name} + peer := newPeer(log.Root(), conn, protocols) + close(peer.closed) // ensures Disconnect doesn't block + return peer +} + // ID returns the node's public key. func (p *Peer) ID() enode.ID { return p.rw.node.ID() diff --git a/p2p/server.go b/p2p/server.go index dbaee12ea..2a38550ab 100644 --- a/p2p/server.go +++ b/p2p/server.go @@ -63,6 +63,9 @@ const ( // Maximum amount of time allowed for writing a complete message. frameWriteTimeout = 20 * time.Second + + // Maximum time to wait before stop the p2p server + stopTimeout = 5 * time.Second ) var errServerStopped = errors.New("server stopped") @@ -403,7 +406,18 @@ func (srv *Server) Stop() { } close(srv.quit) srv.lock.Unlock() - srv.loopWG.Wait() + + stopChan := make(chan struct{}) + go func() { + srv.loopWG.Wait() + close(stopChan) + }() + + select { + case <-stopChan: + case <-time.After(stopTimeout): + srv.log.Warn("stop p2p server timeout, forcing stop") + } } // sharedUDPConn implements a shared connection. Write sends messages to the underlying connection while read returns diff --git a/params/version.go b/params/version.go index 07713c553..c90a95a46 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 1 // Major version component of the current release VersionMinor = 0 // Minor version component of the current release - VersionPatch = 1 // Patch version component of the current release + VersionPatch = 2 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) diff --git a/trie/proof.go b/trie/proof.go index 08a9e4042..80227149e 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -472,12 +472,17 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, lastKey []byte, key if len(keys) != len(values) { return false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values)) } - // Ensure the received batch is monotonic increasing. + // Ensure the received batch is monotonic increasing and contains no deletions. for i := 0; i < len(keys)-1; i++ { if bytes.Compare(keys[i], keys[i+1]) >= 0 { return false, errors.New("range is not monotonically increasing") } } + for _, value := range values { + if len(value) == 0 { + return false, errors.New("range contains deletion") + } + } // Special case, there is no edge proof at all. The given range is expected // to be the whole leaf-set in the trie. if proof == nil { diff --git a/trie/trie.go b/trie/trie.go index 44de1374a..1e6e8fd25 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -174,6 +174,10 @@ func (t *Trie) TryGetNode(path []byte) ([]byte, int, error) { } func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, newnode node, resolved int, err error) { + // If non-existent path requested, abort + if origNode == nil { + return nil, nil, 0, nil + } // If we reached the requested path, return the current node if pos >= len(path) { // Although we most probably have the original node expanded, encoding @@ -193,10 +197,6 @@ func (t *Trie) tryGetNode(origNode node, path []byte, pos int) (item []byte, new } // Path still needs to be traversed, descend into children switch n := (origNode).(type) { - case nil: - // Non-existent path requested, abort - return nil, nil, 0, nil - case valueNode: // Path prematurely ended, abort return nil, nil, 0, nil