From 4bb5c6ca7a19f5ad0230879205380adaca12ef4f Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Thu, 7 Jan 2021 17:12:41 +0100 Subject: [PATCH] eth/protocols/snap: speed up hash checks (#22023) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * eth/protocols/snap: speed up hash checks * eth/protocols/snap: nit fix Co-authored-by: Péter Szilágyi --- eth/protocols/snap/sync.go | 15 +++-- eth/protocols/snap/sync_test.go | 98 +++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 eth/protocols/snap/sync_test.go diff --git a/eth/protocols/snap/sync.go b/eth/protocols/snap/sync.go index 82b21c470..d6f0eb547 100644 --- a/eth/protocols/snap/sync.go +++ b/eth/protocols/snap/sync.go @@ -2112,14 +2112,15 @@ func (s *Syncer) onByteCodes(peer *Peer, id uint64, bytecodes [][]byte) error { // Cross reference the requested bytecodes with the response to find gaps // that the serving node is missing - hasher := sha3.NewLegacyKeccak256() + hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) + hash := make([]byte, 32) codes := make([][]byte, len(req.hashes)) for i, j := 0, 0; i < len(bytecodes); i++ { // Find the next hash that we've been served, leaving misses with nils hasher.Reset() hasher.Write(bytecodes[i]) - hash := hasher.Sum(nil) + hasher.Read(hash) for j < len(req.hashes) && !bytes.Equal(hash, req.hashes[j][:]) { j++ @@ -2350,14 +2351,15 @@ func (s *Syncer) OnTrieNodes(peer *Peer, id uint64, trienodes [][]byte) error { // Cross reference the requested trienodes with the response to find gaps // that the serving node is missing - hasher := sha3.NewLegacyKeccak256() + hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) + hash := make([]byte, 32) nodes := make([][]byte, len(req.hashes)) for i, j := 0, 0; i < len(trienodes); i++ { // Find the next hash that we've been served, leaving misses with nils hasher.Reset() hasher.Write(trienodes[i]) - hash := hasher.Sum(nil) + hasher.Read(hash) for j < len(req.hashes) && !bytes.Equal(hash, req.hashes[j][:]) { j++ @@ -2437,14 +2439,15 @@ func (s *Syncer) onHealByteCodes(peer *Peer, id uint64, bytecodes [][]byte) erro // Cross reference the requested bytecodes with the response to find gaps // that the serving node is missing - hasher := sha3.NewLegacyKeccak256() + hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) + hash := make([]byte, 32) codes := make([][]byte, len(req.hashes)) for i, j := 0, 0; i < len(bytecodes); i++ { // Find the next hash that we've been served, leaving misses with nils hasher.Reset() hasher.Write(bytecodes[i]) - hash := hasher.Sum(nil) + hasher.Read(hash) for j < len(req.hashes) && !bytes.Equal(hash, req.hashes[j][:]) { j++ diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go new file mode 100644 index 000000000..4f28b99bf --- /dev/null +++ b/eth/protocols/snap/sync_test.go @@ -0,0 +1,98 @@ +// Copyright 2020 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 snap + +import ( + "crypto/rand" + "fmt" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "golang.org/x/crypto/sha3" +) + +func TestHashing(t *testing.T) { + var bytecodes = make([][]byte, 10) + for i := 0; i < len(bytecodes); i++ { + buf := make([]byte, 100) + rand.Read(buf) + bytecodes[i] = buf + } + var want, got string + var old = func() { + hasher := sha3.NewLegacyKeccak256() + for i := 0; i < len(bytecodes); i++ { + hasher.Reset() + hasher.Write(bytecodes[i]) + hash := hasher.Sum(nil) + got = fmt.Sprintf("%v\n%v", got, hash) + } + } + var new = func() { + hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) + var hash = make([]byte, 32) + for i := 0; i < len(bytecodes); i++ { + hasher.Reset() + hasher.Write(bytecodes[i]) + hasher.Read(hash) + want = fmt.Sprintf("%v\n%v", want, hash) + } + } + old() + new() + if want != got { + t.Errorf("want\n%v\ngot\n%v\n", want, got) + } +} + +func BenchmarkHashing(b *testing.B) { + var bytecodes = make([][]byte, 10000) + for i := 0; i < len(bytecodes); i++ { + buf := make([]byte, 100) + rand.Read(buf) + bytecodes[i] = buf + } + var old = func() { + hasher := sha3.NewLegacyKeccak256() + for i := 0; i < len(bytecodes); i++ { + hasher.Reset() + hasher.Write(bytecodes[i]) + hasher.Sum(nil) + } + } + var new = func() { + hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState) + var hash = make([]byte, 32) + for i := 0; i < len(bytecodes); i++ { + hasher.Reset() + hasher.Write(bytecodes[i]) + hasher.Read(hash) + } + } + b.Run("old", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + old() + } + }) + b.Run("new", func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + new() + } + }) +}