Skip to content

Commit

Permalink
atx: cache poet proofs with lru
Browse files Browse the repository at this point in the history
  • Loading branch information
dshulyak committed Sep 18, 2024
1 parent 5091028 commit b6a258d
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 4 deletions.
2 changes: 2 additions & 0 deletions activation/activation.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type PoetConfig struct {
InfoCacheTTL time.Duration `mapstructure:"info-cache-ttl"`
PowParamsCacheTTL time.Duration `mapstructure:"pow-params-cache-ttl"`
MaxRequestRetries int `mapstructure:"retry-max"`
PoetProofsCache int `mapstructure:"poet-proofs-cache"`
}

func DefaultPoetConfig() PoetConfig {
Expand All @@ -62,6 +63,7 @@ func DefaultPoetConfig() PoetConfig {
MaxRequestRetries: 10,
InfoCacheTTL: 5 * time.Minute,
PowParamsCacheTTL: 5 * time.Minute,
PoetProofsCache: 200,
}
}

Expand Down
61 changes: 57 additions & 4 deletions activation/poetdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"context"
"encoding/hex"
"fmt"
"sync"

lru "github.com/hashicorp/golang-lru/v2"
"github.com/spacemeshos/merkle-tree"
"github.com/spacemeshos/poet/hash"
"github.com/spacemeshos/poet/shared"
Expand All @@ -19,19 +21,58 @@ import (
"github.com/spacemeshos/go-spacemesh/sql/poets"
)

// PoetDbOptions are options for PoetDb.
type PoetDbOptions struct {
cacheSize int
}

type PoetDbOption func(*PoetDbOptions)

// WithCacheSize sets the cache size for PoetDb.
func WithCacheSize(size int) PoetDbOption {
return func(opts *PoetDbOptions) {
opts.cacheSize = size

Check warning on line 34 in activation/poetdb.go

View check run for this annotation

Codecov / codecov/patch

activation/poetdb.go#L32-L34

Added lines #L32 - L34 were not covered by tests
}
}

// PoetDb is a database for PoET proofs.
type PoetDb struct {
sqlDB sql.StateDatabase
logger *zap.Logger
sqlDB sql.StateDatabase
singleQueryMu sync.Mutex // see comment where it is used
poetProofsLru *lru.Cache[types.PoetProofRef, *types.PoetProofMessage]
logger *zap.Logger
}

// NewPoetDb returns a new PoET handler.
func NewPoetDb(db sql.StateDatabase, log *zap.Logger) *PoetDb {
return &PoetDb{sqlDB: db, logger: log}
func NewPoetDb(db sql.StateDatabase, log *zap.Logger, opts ...PoetDbOption) *PoetDb {
options := PoetDbOptions{
// in last epochs there are 45 proofs per epoch, with each of them nearly 140KB
// 200 is set not to keep multiple epochs, but to account for unexpected growth
// select round_id, count(*), max(length(poet)) from poets group by round_id;
// 25|42|146200
// 26|45|145936
// 27|45|145738
// 28|45|145903
cacheSize: 200,
}
for _, opt := range opts {
opt(&options)

Check warning on line 59 in activation/poetdb.go

View check run for this annotation

Codecov / codecov/patch

activation/poetdb.go#L59

Added line #L59 was not covered by tests
}
poetProofsLru, err := lru.New[types.PoetProofRef, *types.PoetProofMessage](options.cacheSize)
if err != nil {
log.Panic("failed to create PoET proofs LRU cache", zap.Error(err))

Check warning on line 63 in activation/poetdb.go

View check run for this annotation

Codecov / codecov/patch

activation/poetdb.go#L63

Added line #L63 was not covered by tests
}
return &PoetDb{
sqlDB: db,
poetProofsLru: poetProofsLru,
logger: log}

Check failure on line 68 in activation/poetdb.go

View workflow job for this annotation

GitHub Actions / lint

File is not `gofumpt`-ed with `-extra` (gofumpt)
}

// HasProof returns true if the database contains a proof with the given reference, or false otherwise.
func (db *PoetDb) HasProof(proofRef types.PoetProofRef) bool {
if db.poetProofsLru.Contains(proofRef) {
return true
}
has, err := poets.Has(db.sqlDB, proofRef)
return err == nil && has
}
Expand Down Expand Up @@ -99,6 +140,7 @@ func (db *PoetDb) Validate(

// StoreProof saves the poet proof in local db.
func (db *PoetDb) StoreProof(ctx context.Context, ref types.PoetProofRef, proofMessage *types.PoetProofMessage) error {
db.poetProofsLru.Add(ref, proofMessage)
messageBytes, err := codec.Encode(proofMessage)
if err != nil {
return fmt.Errorf("could not marshal proof message: %w", err)
Expand Down Expand Up @@ -146,6 +188,16 @@ func (db *PoetDb) GetProofMessage(proofRef types.PoetProofRef) ([]byte, error) {

// Proof returns full proof.
func (db *PoetDb) Proof(proofRef types.PoetProofRef) (*types.PoetProof, *types.Hash32, error) {
// there is no effective rate limiting on gossip layer, and most of the proofs are reused
// hence to avoid excessive reads during atx "storm" we do them sequentially
// additionally poet proof can be cached during ValidateAndStore routine
db.singleQueryMu.Lock()
defer db.singleQueryMu.Unlock()
cachedProof, ok := db.poetProofsLru.Get(proofRef)
if ok && cachedProof != nil {
return &cachedProof.PoetProof, &cachedProof.Statement, nil
}

proofMessageBytes, err := db.GetProofMessage(proofRef)
if err != nil {
return nil, nil, fmt.Errorf("could not fetch poet proof for ref %x: %w", proofRef, err)
Expand All @@ -154,6 +206,7 @@ func (db *PoetDb) Proof(proofRef types.PoetProofRef) (*types.PoetProof, *types.H
if err := codec.Decode(proofMessageBytes, &proofMessage); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal poet proof for ref %x: %w", proofRef, err)
}
db.poetProofsLru.Add(proofRef, &proofMessage)

Check warning on line 209 in activation/poetdb.go

View check run for this annotation

Codecov / codecov/patch

activation/poetdb.go#L209

Added line #L209 was not covered by tests
return &proofMessage.PoetProof, &proofMessage.Statement, nil
}

Expand Down
1 change: 1 addition & 0 deletions config/mainnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ func MainnetConfig() Config {
RequestTimeout: 1100 * time.Second,
RequestRetryDelay: 10 * time.Second,
MaxRequestRetries: 10,
PoetProofsCache: 200,
},
POST: activation.PostConfig{
MinNumUnits: 4,
Expand Down
1 change: 1 addition & 0 deletions config/presets/testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ func testnet() config.Config {

InfoCacheTTL: 5 * time.Minute,
PowParamsCacheTTL: 5 * time.Minute,
PoetProofsCache: 200,
},
POST: activation.PostConfig{
MinNumUnits: 2,
Expand Down

0 comments on commit b6a258d

Please sign in to comment.