Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - atx: cache poet proofs with lru #6336

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
"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 @@
"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 {
poszu marked this conversation as resolved.
Show resolved Hide resolved
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
}
poszu marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -99,6 +140,7 @@

// 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 @@

// 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
}
poszu marked this conversation as resolved.
Show resolved Hide resolved

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 @@
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
Loading