keys: add simple LRU key cache for 1024 elements

The cost of Y calculation from X is comparable with signature check, so it
reduces witness check overhead by ~30% for cached keys and gives ~5% overall
boost in TPS.
This commit is contained in:
Roman Khimov 2020-08-29 22:37:31 +03:00
parent 0ea8c8ba67
commit f5f58a7e91
4 changed files with 27 additions and 1 deletions

1
go.mod
View file

@ -8,6 +8,7 @@ require (
github.com/frankban/quicktest v1.10.0 // indirect
github.com/go-redis/redis v6.10.2+incompatible
github.com/gorilla/websocket v1.4.2
github.com/hashicorp/golang-lru v0.5.4
github.com/mr-tron/base58 v1.1.2
github.com/nspcc-dev/dbft v0.0.0-20200711144034-c526ccc6f570
github.com/nspcc-dev/rfc6979 v0.2.0

2
go.sum
View file

@ -110,6 +110,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=

View file

@ -11,6 +11,7 @@ import (
"math/big"
"github.com/btcsuite/btcd/btcec"
lru "github.com/hashicorp/golang-lru"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
@ -105,13 +106,31 @@ func NewPublicKeyFromString(s string) (*PublicKey, error) {
return NewPublicKeyFromBytes(b, elliptic.P256())
}
// keycache is a simple lru cache for P256 keys that avoids Y calculation overhead
// for known keys.
var keycache *lru.Cache
func init() {
// Less than 100K, probably enough for our purposes.
keycache, _ = lru.New(1024)
}
// NewPublicKeyFromBytes returns public key created from b using given EC.
func NewPublicKeyFromBytes(b []byte, curve elliptic.Curve) (*PublicKey, error) {
pubKey := new(PublicKey)
var pubKey *PublicKey
cachedKey, ok := keycache.Get(string(b))
if ok {
pubKey = cachedKey.(*PublicKey)
if pubKey.Curve == curve {
return pubKey, nil
}
}
pubKey = new(PublicKey)
pubKey.Curve = curve
if err := pubKey.DecodeBytes(b); err != nil {
return nil, err
}
keycache.Add(string(b), pubKey)
return pubKey, nil
}

View file

@ -63,6 +63,10 @@ func TestNewPublicKeyFromBytes(t *testing.T) {
pub, err := NewPublicKeyFromBytes(b, elliptic.P256())
require.NoError(t, err)
require.Equal(t, priv.PublicKey(), pub)
// Test cached access
pub2, err := NewPublicKeyFromBytes(b, elliptic.P256())
require.NoError(t, err)
require.Same(t, pub, pub2)
}
func TestDecodeFromString(t *testing.T) {