Ori Newman afaac28da1
Validate each level parents (#1827)
* Create BlockParentBuilder.

* Implement BuildParents.

* Explictly set level 0 blocks to be the same as direct parents.

* Add checkIndirectParents to validateBlockHeaderInContext.

* Fix test_block_builder.go and BlockLevelParents::Equal.

* Don't check indirect parents for blocks with trusted data.

* Handle pruned blocks when building block level parents.

* Fix bad deletions from unprocessedXxxParents.

* Fix merge errors.

* Fix bad pruning point parent replaces.

* Fix duplicates in newBlockLevelParents.

* Skip checkIndirectParents

* Get rid of staging constant IDs

* Fix BuildParents

* Fix tests

* Add comments

* Change order of directParentHashes

* Get rid of maybeAddDirectParentParents

* Add comments

* Add blockToReferences type

* Use ParentsAtLevel

Co-authored-by: stasatdaglabs <stas@daglabs.com>
2021-09-13 14:22:00 +03:00

94 lines
2.8 KiB
Go

package multisetstore
import (
"github.com/golang/protobuf/proto"
"github.com/kaspanet/kaspad/domain/consensus/database/serialization"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/lrucache"
"github.com/kaspanet/kaspad/util/staging"
)
var bucketName = []byte("multisets")
// multisetStore represents a store of Multisets
type multisetStore struct {
shardID model.StagingShardID
cache *lrucache.LRUCache
bucket model.DBBucket
}
// New instantiates a new MultisetStore
func New(prefixBucket model.DBBucket, cacheSize int, preallocate bool) model.MultisetStore {
return &multisetStore{
shardID: staging.GenerateShardingID(),
cache: lrucache.New(cacheSize, preallocate),
bucket: prefixBucket.Bucket(bucketName),
}
}
// Stage stages the given multiset for the given blockHash
func (ms *multisetStore) Stage(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash, multiset model.Multiset) {
stagingShard := ms.stagingShard(stagingArea)
stagingShard.toAdd[*blockHash] = multiset.Clone()
}
func (ms *multisetStore) IsStaged(stagingArea *model.StagingArea) bool {
return ms.stagingShard(stagingArea).isStaged()
}
// Get gets the multiset associated with the given blockHash
func (ms *multisetStore) Get(dbContext model.DBReader, stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (model.Multiset, error) {
stagingShard := ms.stagingShard(stagingArea)
if multiset, ok := stagingShard.toAdd[*blockHash]; ok {
return multiset.Clone(), nil
}
if multiset, ok := ms.cache.Get(blockHash); ok {
return multiset.(model.Multiset).Clone(), nil
}
multisetBytes, err := dbContext.Get(ms.hashAsKey(blockHash))
if err != nil {
return nil, err
}
multiset, err := ms.deserializeMultiset(multisetBytes)
if err != nil {
return nil, err
}
ms.cache.Add(blockHash, multiset)
return multiset.Clone(), nil
}
// Delete deletes the multiset associated with the given blockHash
func (ms *multisetStore) Delete(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) {
stagingShard := ms.stagingShard(stagingArea)
if _, ok := stagingShard.toAdd[*blockHash]; ok {
delete(stagingShard.toAdd, *blockHash)
return
}
stagingShard.toDelete[*blockHash] = struct{}{}
}
func (ms *multisetStore) hashAsKey(hash *externalapi.DomainHash) model.DBKey {
return ms.bucket.Key(hash.ByteSlice())
}
func (ms *multisetStore) serializeMultiset(multiset model.Multiset) ([]byte, error) {
return proto.Marshal(serialization.MultisetToDBMultiset(multiset))
}
func (ms *multisetStore) deserializeMultiset(multisetBytes []byte) (model.Multiset, error) {
dbMultiset := &serialization.DbMultiset{}
err := proto.Unmarshal(multisetBytes, dbMultiset)
if err != nil {
return nil, err
}
return serialization.DBMultisetToMultiset(dbMultiset)
}