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 all commits
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
77 changes: 66 additions & 11 deletions activation/poetdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
"encoding/hex"
"fmt"

lru "github.com/hashicorp/golang-lru/v2"
"github.com/spacemeshos/merkle-tree"
"github.com/spacemeshos/poet/hash"
"github.com/spacemeshos/poet/shared"
"github.com/spacemeshos/poet/verifier"
"go.uber.org/zap"
"golang.org/x/sync/singleflight"

"github.com/spacemeshos/go-spacemesh/codec"
"github.com/spacemeshos/go-spacemesh/common/types"
Expand All @@ -19,19 +21,59 @@
"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
}
}

// PoetDb is a database for PoET proofs.
type PoetDb struct {
sqlDB sql.StateDatabase
logger *zap.Logger
sqlDB sql.StateDatabase
poetProofsDbRequest singleflight.Group
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)
}
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,
}
}

// 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 +141,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,15 +189,27 @@

// Proof returns full proof.
func (db *PoetDb) Proof(proofRef types.PoetProofRef) (*types.PoetProof, *types.Hash32, error) {
proofMessageBytes, err := db.GetProofMessage(proofRef)
response, err, _ := db.poetProofsDbRequest.Do(string(proofRef[:]), func() (any, error) {
cachedProof, ok := db.poetProofsLru.Get(proofRef)
if ok && cachedProof != nil {
return cachedProof, nil
}
proofMessageBytes, err := db.GetProofMessage(proofRef)
if err != nil {
return nil, fmt.Errorf("could not fetch poet proof for ref %x: %w", proofRef, err)

Check warning on line 199 in activation/poetdb.go

View check run for this annotation

Codecov / codecov/patch

activation/poetdb.go#L197-L199

Added lines #L197 - L199 were not covered by tests
}
var proofMessage types.PoetProofMessage
if err := codec.Decode(proofMessageBytes, &proofMessage); err != nil {
return nil, fmt.Errorf("failed to unmarshal poet proof for ref %x: %w", proofRef, err)

Check warning on line 203 in activation/poetdb.go

View check run for this annotation

Codecov / codecov/patch

activation/poetdb.go#L201-L203

Added lines #L201 - L203 were not covered by tests
}
db.poetProofsLru.Add(proofRef, &proofMessage)
return &proofMessage, nil

Check warning on line 206 in activation/poetdb.go

View check run for this annotation

Codecov / codecov/patch

activation/poetdb.go#L205-L206

Added lines #L205 - L206 were not covered by tests
})
if err != nil {
return nil, nil, fmt.Errorf("could not fetch poet proof for ref %x: %w", proofRef, err)
}
var proofMessage types.PoetProofMessage
if err := codec.Decode(proofMessageBytes, &proofMessage); err != nil {
return nil, nil, fmt.Errorf("failed to unmarshal poet proof for ref %x: %w", proofRef, err)
return nil, nil, err

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
proof := response.(*types.PoetProofMessage)
return &proof.PoetProof, &proof.Statement, nil
}

func (db *PoetDb) ProofForRound(poetID []byte, roundID string) (*types.PoetProof, error) {
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
5 changes: 4 additions & 1 deletion node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,10 @@ func (app *App) initServices(ctx context.Context) error {
layersPerEpoch := types.GetLayersPerEpoch()
lg := app.log

poetDb := activation.NewPoetDb(app.db, app.addLogger(PoetDbLogger, lg).Zap())
poetDb := activation.NewPoetDb(
app.db,
app.addLogger(PoetDbLogger, lg).Zap(),
activation.WithCacheSize(app.Config.POET.PoetProofsCache))
postStates := activation.NewPostStates(app.addLogger(PostLogger, lg).Zap())
opts := []activation.PostVerifierOpt{
activation.WithVerifyingOpts(app.Config.SMESHING.VerifyingOpts),
Expand Down
Loading