Compare commits

..

9 Commits

Author SHA1 Message Date
Ori Newman
b510fc08a7 Change PoW error (#1234)
* Use proper error for invalid PoW

* Add comment
2020-12-16 13:33:10 +02:00
Ori Newman
dc3ae4d3ac Use pointer receivers when needed (#1237) 2020-12-16 12:50:17 +02:00
Svarog
1ebda36b17 Remove IsAwaitingUTXOSet from validateAndInsertBlock log, to prevent long operation (#1235) 2020-12-16 11:33:48 +02:00
Ori Newman
12379bedb6 Fix UTXO serialization errors (#1233) 2020-12-16 11:27:43 +02:00
stasatdaglabs
f90d7d796a [NOD-1593] Return SelectedParentChainChanged from ValidateAndInsertBlock (#1202)
* [NOD-1579] Rename AcceptedTxIDs to AcceptedTransactionIDs.

* [NOD-1579] Add InsertBlockResult to ValidateAndInsertBlock results.

* [NOD-1593] Rename InsertBlockResult to BlockInsertionResult.

* [NOD-1593] Add SelectedParentChainChanges to AddBlockToVirtual's result.

* [NOD-1593] Implement findSelectedParentChainChanges.

* [NOD-1593] Implement TestFindSelectedParentChainChanges.

* [NOD-1593] Fix a string.

* [NOD-1593] Finish implementing TestFindSelectedParentChainChanges.

* [NOD-1593] Fix merge errors.

* [NOD-1593] Fix merge errors.

* [NOD-1593] Rename findSelectedParentChainChanges to calculateSelectedParentChainChanges.

* [NOD-1593] Expand TestCalculateSelectedParentChainChanges.
2020-12-15 11:37:52 +02:00
Ori Newman
fddda46d4f Fix infinite loop on antiPastHashesBetween (#1226)
* Fix infinite loop on antiPastHashesBetween

* Get rid of highBlockBlueScore and lowBlockBlueScore
2020-12-15 10:37:35 +02:00
Svarog
77adb6c99f Make consensus.databaseContext a DBManager and allow keeping data dir in TestConsensus
* Make consensus.databaseContext a DBManager

* Allow keeping data dir in TestConsensus
2020-12-15 10:11:14 +02:00
Ori Newman
48e1a2c396 New headers first flow (#1211)
* Get rid of insertMode

* Rename AddBlockToVirtual->AddBlock

* When F is not in the future of P, enforce finality with P and not with F.

* Don't allow blocks with invalid parents or with missing block body

* Check finality violation before checking block status

* Implement CalculateIndependentPruningPoint

* Move checkBlockStatus to validateBlock

* Add ValidateBlock to block processor interface

* Adjust SetPruningPoint to the new IBD flow

* Add pruning store to CSM's constructor

* Flip wrong condition on AddHeaderTip

* Fix func (hts *headerSelectedTipStore) Has

* Fix block stage order

* Call to ValidateBodyInContext from validatePostProofOfWork

* Enable overrideDAGParams

* Update log

* Rename SetPruningPoint to ValidateAndInsertPruningPoint and move most of its logic inside block processor

* Rename hasValidatedHeader->hasValidatedOnlyHeader

* Fix typo

* Name return values for fetchMissingUTXOSet

* Add comment

* Return ErrMissingParents when block body is missing

* Add logs and comments

* Fix merge error

* Fix pruning point calculation to be by virtual selected parent

* Replace CalculateIndependentPruningPoint to CalculatePruningPointByHeaderSelectedTip

* Fix isAwaitingUTXOSet to check pruning point by headers

* Change isAwaitingUTXOSet indication

* Remove IsBlockInHeaderPruningPointFuture from BlockInfo

* Fix LowestChainBlockAboveOrEqualToBlueScore

* Add validateNewPruningPointTransactions

* Add validateNewPruningAgainstPastUTXO

* Rename set_pruning_utxo_set.go to update_pruning_utxo_set.go

* Check missing block body hashes by missing block instead of status

* Validate pruning point against past UTXO with the pruning point as block hash

* Remove virtualHeaderHash

* Fix comment

* Fix imports
2020-12-14 17:53:08 +02:00
oudeis
6926a7ab81 Update to version 0.8.3 2020-12-14 12:38:03 +00:00
82 changed files with 1485 additions and 1263 deletions

View File

@@ -49,8 +49,8 @@ type ChainBlock struct {
// AcceptedBlock represents a block accepted into the DAG
type AcceptedBlock struct {
Hash string
AcceptedTxIDs []string
Hash string
AcceptedTransactionIDs []string
}
// Command returns the protocol command string for the message

View File

@@ -89,7 +89,7 @@ func (f *FlowContext) SharedRequestedBlocks() *blockrelay.SharedRequestedBlocks
// AddBlock adds the given block to the DAG and propagates it.
func (f *FlowContext) AddBlock(block *externalapi.DomainBlock) error {
err := f.Domain().Consensus().ValidateAndInsertBlock(block)
_, err := f.Domain().Consensus().ValidateAndInsertBlock(block)
if err != nil {
if errors.As(err, &ruleerrors.RuleError{}) {
log.Infof("Validation failed for block %s: %s", consensushashing.BlockHash(block), err)

View File

@@ -116,7 +116,7 @@ func (f *FlowContext) unorphanBlock(orphanHash externalapi.DomainHash) error {
}
delete(f.orphans, orphanHash)
err := f.domain.Consensus().ValidateAndInsertBlock(orphanBlock)
_, err := f.domain.Consensus().ValidateAndInsertBlock(orphanBlock)
if err != nil {
if errors.As(err, &ruleerrors.RuleError{}) {
log.Infof("Validation failed for orphan block %s: %s", orphanHash, err)

View File

@@ -201,7 +201,7 @@ func (flow *handleRelayInvsFlow) readMsgBlock() (msgBlock *appmessage.MsgBlock,
func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([]*externalapi.DomainHash, error) {
blockHash := consensushashing.BlockHash(block)
err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
_, err := flow.Domain().Consensus().ValidateAndInsertBlock(block)
if err != nil {
if !errors.As(err, &ruleerrors.RuleError{}) {
return nil, errors.Wrapf(err, "failed to process block %s", blockHash)
@@ -212,7 +212,6 @@ func (flow *handleRelayInvsFlow) processBlock(block *externalapi.DomainBlock) ([
return missingParentsError.MissingParentHashes, nil
}
log.Warnf("Rejected block %s from %s: %s", blockHash, flow.peer, err)
return nil, protocolerrors.Wrapf(true, err, "got invalid block %s from relay", blockHash)
}
return nil, nil

View File

@@ -35,7 +35,7 @@ func (flow *handleRelayInvsFlow) runIBDIfNotRunning(highHash *externalapi.Domain
if err != nil {
return err
}
if syncInfo.State == externalapi.SyncStateAwaitingUTXOSet {
if syncInfo.IsAwaitingUTXOSet {
found, err := flow.fetchMissingUTXOSet(syncInfo.IBDRootUTXOBlockHash)
if err != nil {
return err
@@ -178,7 +178,7 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo
log.Debugf("Block header %s is already in the DAG. Skipping...", blockHash)
return nil
}
err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
_, err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
if err != nil {
if !errors.As(err, &ruleerrors.RuleError{}) {
return errors.Wrapf(err, "failed to process header %s during IBD", blockHash)
@@ -190,8 +190,8 @@ func (flow *handleRelayInvsFlow) processHeader(msgBlockHeader *appmessage.MsgBlo
return nil
}
func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHash) (bool, error) {
err := flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootUTXOSetAndBlock(ibdRootHash))
func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.DomainHash) (succeed bool, err error) {
err = flow.outgoingRoute.Enqueue(appmessage.NewMsgRequestIBDRootUTXOSetAndBlock(ibdRootHash))
if err != nil {
return false, err
}
@@ -205,17 +205,23 @@ func (flow *handleRelayInvsFlow) fetchMissingUTXOSet(ibdRootHash *externalapi.Do
return false, nil
}
err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
if err != nil {
blockHash := consensushashing.BlockHash(block)
return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "got invalid block %s during IBD", blockHash)
}
err = flow.Domain().Consensus().SetPruningPointUTXOSet(utxoSet)
err = flow.Domain().Consensus().ValidateAndInsertPruningPoint(block, utxoSet)
if err != nil {
return false, protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "error with IBD root UTXO set")
}
syncInfo, err := flow.Domain().Consensus().GetSyncInfo()
if err != nil {
return false, err
}
// TODO: Find a better way to deal with finality conflicts.
if syncInfo.IsAwaitingUTXOSet {
log.Warnf("Still awaiting for UTXO set. This can happen only because the given pruning point violates " +
"finality. If this keeps happening delete the data directory and restart your node.")
return false, nil
}
return true, nil
}
@@ -277,7 +283,7 @@ func (flow *handleRelayInvsFlow) syncMissingBlockBodies(highHash *externalapi.Do
return protocolerrors.Errorf(true, "expected block %s but got %s", expectedHash, blockHash)
}
err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
_, err = flow.Domain().Consensus().ValidateAndInsertBlock(block)
if err != nil {
return protocolerrors.ConvertToBanningProtocolErrorIfRuleError(err, "invalid block %s", blockHash)
}

View File

@@ -11,7 +11,7 @@ import (
type consensus struct {
lock *sync.Mutex
databaseContext model.DBReader
databaseContext model.DBManager
blockProcessor model.BlockProcessor
blockBuilder model.BlockBuilder
@@ -25,25 +25,25 @@ type consensus struct {
dagTraversalManager model.DAGTraversalManager
difficultyManager model.DifficultyManager
ghostdagManager model.GHOSTDAGManager
headerTipsManager model.HeaderTipsManager
headerTipsManager model.HeadersSelectedTipManager
mergeDepthManager model.MergeDepthManager
pruningManager model.PruningManager
reachabilityManager model.ReachabilityManager
finalityManager model.FinalityManager
acceptanceDataStore model.AcceptanceDataStore
blockStore model.BlockStore
blockHeaderStore model.BlockHeaderStore
pruningStore model.PruningStore
ghostdagDataStore model.GHOSTDAGDataStore
blockRelationStore model.BlockRelationStore
blockStatusStore model.BlockStatusStore
consensusStateStore model.ConsensusStateStore
headerTipsStore model.HeaderTipsStore
multisetStore model.MultisetStore
reachabilityDataStore model.ReachabilityDataStore
utxoDiffStore model.UTXODiffStore
finalityStore model.FinalityStore
acceptanceDataStore model.AcceptanceDataStore
blockStore model.BlockStore
blockHeaderStore model.BlockHeaderStore
pruningStore model.PruningStore
ghostdagDataStore model.GHOSTDAGDataStore
blockRelationStore model.BlockRelationStore
blockStatusStore model.BlockStatusStore
consensusStateStore model.ConsensusStateStore
headersSelectedTipStore model.HeaderSelectedTipStore
multisetStore model.MultisetStore
reachabilityDataStore model.ReachabilityDataStore
utxoDiffStore model.UTXODiffStore
finalityStore model.FinalityStore
}
// BuildBlock builds a block over the current state, with the transactions
@@ -59,7 +59,7 @@ func (s *consensus) BuildBlock(coinbaseData *externalapi.DomainCoinbaseData,
// ValidateAndInsertBlock validates the given block and, if valid, applies it
// to the current state
func (s *consensus) ValidateAndInsertBlock(block *externalapi.DomainBlock) error {
func (s *consensus) ValidateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) {
s.lock.Lock()
defer s.lock.Unlock()
@@ -138,12 +138,6 @@ func (s *consensus) GetBlockInfo(blockHash *externalapi.DomainHash) (*externalap
blockInfo.BlueScore = ghostdagData.BlueScore()
isBlockInHeaderPruningPointFuture, err := s.syncManager.IsBlockInHeaderPruningPointFuture(blockHash)
if err != nil {
return nil, err
}
blockInfo.IsBlockInHeaderPruningPointFuture = isBlockInHeaderPruningPointFuture
return blockInfo, nil
}
@@ -183,11 +177,11 @@ func (s *consensus) GetPruningPointUTXOSet(expectedPruningPointHash *externalapi
return serializedUTXOSet, nil
}
func (s *consensus) SetPruningPointUTXOSet(serializedUTXOSet []byte) error {
func (s *consensus) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
s.lock.Lock()
defer s.lock.Unlock()
return s.consensusStateManager.SetPruningPointUTXOSet(serializedUTXOSet)
return s.blockProcessor.ValidateAndInsertPruningPoint(newPruningPoint, serializedUTXOSet)
}
func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error) {
@@ -201,27 +195,6 @@ func (s *consensus) GetVirtualSelectedParent() (*externalapi.DomainBlock, error)
return s.blockStore.Block(s.databaseContext, virtualGHOSTDAGData.SelectedParent())
}
func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) {
s.lock.Lock()
defer s.lock.Unlock()
return s.syncManager.CreateBlockLocator(lowHash, highHash, limit)
}
func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) {
s.lock.Lock()
defer s.lock.Unlock()
return s.syncManager.FindNextBlockLocatorBoundaries(blockLocator)
}
func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) {
s.lock.Lock()
defer s.lock.Unlock()
return s.syncManager.GetSyncInfo()
}
func (s *consensus) Tips() ([]*externalapi.DomainHash, error) {
return s.consensusStateStore.Tips(s.databaseContext)
}
@@ -246,3 +219,24 @@ func (s *consensus) GetVirtualInfo() (*externalapi.VirtualInfo, error) {
PastMedianTime: pastMedianTime,
}, nil
}
func (s *consensus) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) {
s.lock.Lock()
defer s.lock.Unlock()
return s.syncManager.CreateBlockLocator(lowHash, highHash, limit)
}
func (s *consensus) FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error) {
s.lock.Lock()
defer s.lock.Unlock()
return s.syncManager.FindNextBlockLocatorBoundaries(blockLocator)
}
func (s *consensus) GetSyncInfo() (*externalapi.SyncInfo, error) {
s.lock.Lock()
defer s.lock.Unlock()
return s.syncManager.GetSyncInfo()
}

View File

@@ -19,14 +19,14 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
invalidBlock, _, err := consensus.BuildBlockWithParents([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatal(err)
}
invalidBlock.Header.TimeInMilliseconds = 0
err = consensus.ValidateAndInsertBlock(invalidBlock)
_, err = consensus.ValidateAndInsertBlock(invalidBlock)
if !errors.Is(err, ruleerrors.ErrTimeTooOld) {
t.Fatalf("Expected block to be invalid with err: %v, instead found: %v", ruleerrors.ErrTimeTooOld, err)
}
@@ -42,9 +42,6 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
if info.BlockStatus != externalapi.StatusInvalid {
t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusInvalid, info.BlockStatus)
}
if info.IsBlockInHeaderPruningPointFuture != false {
t.Fatalf("Expected IsBlockInHeaderPruningPointFuture=false, instead found: %t", info.IsBlockInHeaderPruningPointFuture)
}
emptyCoinbase := externalapi.DomainCoinbaseData{}
validBlock, err := consensus.BuildBlock(&emptyCoinbase, nil)
@@ -52,7 +49,7 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
t.Fatalf("consensus.BuildBlock with an empty coinbase shouldn't fail: %v", err)
}
err = consensus.ValidateAndInsertBlock(validBlock)
_, err = consensus.ValidateAndInsertBlock(validBlock)
if err != nil {
t.Fatalf("consensus.ValidateAndInsertBlock with a block straight from consensus.BuildBlock should not fail: %v", err)
}
@@ -68,9 +65,6 @@ func TestConsensus_GetBlockInfo(t *testing.T) {
if info.BlockStatus != externalapi.StatusValid {
t.Fatalf("Expected block status: %s, instead got: %s", externalapi.StatusValid, info.BlockStatus)
}
if info.IsBlockInHeaderPruningPointFuture != true {
t.Fatalf("Expected IsBlockInHeaderPruningPointFuture=true, instead found: %t", info.IsBlockInHeaderPruningPointFuture)
}
})
}

View File

@@ -0,0 +1,100 @@
package headersselectedtipstore
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/dbkeys"
)
var headerSelectedTipKey = dbkeys.MakeBucket().Key([]byte("headers-selected-tip"))
type headerSelectedTipStore struct {
staging *externalapi.DomainHash
cache *externalapi.DomainHash
}
// New instantiates a new HeaderSelectedTipStore
func New() model.HeaderSelectedTipStore {
return &headerSelectedTipStore{}
}
func (hts *headerSelectedTipStore) Has(dbContext model.DBReader) (bool, error) {
if hts.staging != nil {
return true, nil
}
if hts.cache != nil {
return true, nil
}
return dbContext.Has(headerSelectedTipKey)
}
func (hts *headerSelectedTipStore) Discard() {
hts.staging = nil
}
func (hts *headerSelectedTipStore) Commit(dbTx model.DBTransaction) error {
if hts.staging == nil {
return nil
}
selectedTipBytes, err := hts.serializeHeadersSelectedTip(hts.staging)
if err != nil {
return err
}
err = dbTx.Put(headerSelectedTipKey, selectedTipBytes)
if err != nil {
return err
}
hts.cache = hts.staging
hts.Discard()
return nil
}
func (hts *headerSelectedTipStore) Stage(selectedTip *externalapi.DomainHash) {
hts.staging = selectedTip.Clone()
}
func (hts *headerSelectedTipStore) IsStaged() bool {
return hts.staging != nil
}
func (hts *headerSelectedTipStore) HeadersSelectedTip(dbContext model.DBReader) (*externalapi.DomainHash, error) {
if hts.staging != nil {
return hts.staging.Clone(), nil
}
if hts.cache != nil {
return hts.cache.Clone(), nil
}
selectedTipBytes, err := dbContext.Get(headerSelectedTipKey)
if err != nil {
return nil, err
}
selectedTip, err := hts.deserializeHeadersSelectedTip(selectedTipBytes)
if err != nil {
return nil, err
}
hts.cache = selectedTip
return hts.cache.Clone(), nil
}
func (hts *headerSelectedTipStore) serializeHeadersSelectedTip(selectedTip *externalapi.DomainHash) ([]byte, error) {
return proto.Marshal(serialization.DomainHashToDbHash(selectedTip))
}
func (hts *headerSelectedTipStore) deserializeHeadersSelectedTip(selectedTipBytes []byte) (*externalapi.DomainHash, error) {
dbHash := &serialization.DbHash{}
err := proto.Unmarshal(selectedTipBytes, dbHash)
if err != nil {
return nil, err
}
return serialization.DbHashToDomainHash(dbHash)
}

View File

@@ -1,101 +0,0 @@
package headertipsstore
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/dbkeys"
)
var headerTipsKey = dbkeys.MakeBucket().Key([]byte("header-tips"))
type headerTipsStore struct {
staging []*externalapi.DomainHash
cache []*externalapi.DomainHash
}
// New instantiates a new HeaderTipsStore
func New() model.HeaderTipsStore {
return &headerTipsStore{}
}
func (hts *headerTipsStore) HasTips(dbContext model.DBReader) (bool, error) {
if len(hts.staging) > 0 {
return true, nil
}
if len(hts.cache) > 0 {
return true, nil
}
return dbContext.Has(headerTipsKey)
}
func (hts *headerTipsStore) Discard() {
hts.staging = nil
}
func (hts *headerTipsStore) Commit(dbTx model.DBTransaction) error {
if hts.staging == nil {
return nil
}
tipsBytes, err := hts.serializeTips(hts.staging)
if err != nil {
return err
}
err = dbTx.Put(headerTipsKey, tipsBytes)
if err != nil {
return err
}
hts.cache = hts.staging
hts.Discard()
return nil
}
func (hts *headerTipsStore) Stage(tips []*externalapi.DomainHash) {
hts.staging = externalapi.CloneHashes(tips)
}
func (hts *headerTipsStore) IsStaged() bool {
return hts.staging != nil
}
func (hts *headerTipsStore) Tips(dbContext model.DBReader) ([]*externalapi.DomainHash, error) {
if hts.staging != nil {
return externalapi.CloneHashes(hts.staging), nil
}
if hts.cache != nil {
return externalapi.CloneHashes(hts.cache), nil
}
tipsBytes, err := dbContext.Get(headerTipsKey)
if err != nil {
return nil, err
}
tips, err := hts.deserializeTips(tipsBytes)
if err != nil {
return nil, err
}
hts.cache = tips
return externalapi.CloneHashes(tips), nil
}
func (hts *headerTipsStore) serializeTips(tips []*externalapi.DomainHash) ([]byte, error) {
dbTips := serialization.HeaderTipsToDBHeaderTips(tips)
return proto.Marshal(dbTips)
}
func (hts *headerTipsStore) deserializeTips(tipsBytes []byte) ([]*externalapi.DomainHash, error) {
dbTips := &serialization.DbHeaderTips{}
err := proto.Unmarshal(tipsBytes, dbTips)
if err != nil {
return nil, err
}
return serialization.DBHeaderTipsToHeaderTips(dbTips)
}

View File

@@ -17,7 +17,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/datastructures/consensusstatestore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/finalitystore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/ghostdagdatastore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headertipsstore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/headersselectedtipstore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/multisetstore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/pruningstore"
"github.com/kaspanet/kaspad/domain/consensus/datastructures/reachabilitydatastore"
@@ -32,7 +32,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/processes/dagtopologymanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/difficultymanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/ghostdagmanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/headertipsmanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/headersselectedtipmanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/mergedepthmanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/pastmediantimemanager"
"github.com/kaspanet/kaspad/domain/consensus/processes/pruningmanager"
@@ -47,9 +47,10 @@ import (
// Factory instantiates new Consensuses
type Factory interface {
NewConsensus(dagParams *dagconfig.Params, db infrastructuredatabase.Database) (externalapi.Consensus, error)
NewTestConsensus(dagParams *dagconfig.Params, testName string) (tc testapi.TestConsensus, teardown func(), err error)
NewTestConsensus(dagParams *dagconfig.Params, testName string) (
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error)
NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string) (
tc testapi.TestConsensus, teardown func(), err error)
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error)
}
type factory struct{}
@@ -81,7 +82,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
utxoDiffStore := utxodiffstore.New(200)
consensusStateStore := consensusstatestore.New()
ghostdagDataStore := ghostdagdatastore.New(10_000)
headerTipsStore := headertipsstore.New()
headersSelectedTipStore := headersselectedtipstore.New()
finalityStore := finalitystore.New(200)
// Processes
@@ -139,7 +140,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
dagParams.CoinbasePayloadScriptPublicKeyMaxLength,
ghostdagDataStore,
acceptanceDataStore)
headerTipsManager := headertipsmanager.New(dbManager, dagTopologyManager, ghostdagManager, headerTipsStore)
headerTipsManager := headersselectedtipmanager.New(dbManager, dagTopologyManager, ghostdagManager, headersSelectedTipStore)
genesisHash := dagParams.GenesisHash
finalityManager := finalitymanager.New(
dbManager,
@@ -211,7 +212,8 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
blockRelationStore,
acceptanceDataStore,
blockHeaderStore,
headerTipsStore)
headersSelectedTipStore,
pruningStore)
if err != nil {
return nil, err
}
@@ -225,6 +227,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
ghostdagDataStore,
pruningStore,
blockStatusStore,
headersSelectedTipStore,
multisetStore,
acceptanceDataStore,
blockStore,
@@ -236,17 +239,16 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
syncManager := syncmanager.New(
dbManager,
genesisHash,
dagParams.TargetTimePerBlock.Milliseconds(),
dagTraversalManager,
dagTopologyManager,
ghostdagManager,
consensusStateManager,
pruningManager,
ghostdagDataStore,
blockStatusStore,
blockHeaderStore,
headerTipsStore,
blockStore)
blockStore,
pruningStore)
blockBuilder := blockbuilder.New(
dbManager,
@@ -287,7 +289,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
reachabilityDataStore,
utxoDiffStore,
blockHeaderStore,
headerTipsStore,
headersSelectedTipStore,
finalityStore)
c := &consensus{
@@ -312,19 +314,19 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
reachabilityManager: reachabilityManager,
finalityManager: finalityManager,
acceptanceDataStore: acceptanceDataStore,
blockStore: blockStore,
blockHeaderStore: blockHeaderStore,
pruningStore: pruningStore,
ghostdagDataStore: ghostdagDataStore,
blockStatusStore: blockStatusStore,
blockRelationStore: blockRelationStore,
consensusStateStore: consensusStateStore,
headerTipsStore: headerTipsStore,
multisetStore: multisetStore,
reachabilityDataStore: reachabilityDataStore,
utxoDiffStore: utxoDiffStore,
finalityStore: finalityStore,
acceptanceDataStore: acceptanceDataStore,
blockStore: blockStore,
blockHeaderStore: blockHeaderStore,
pruningStore: pruningStore,
ghostdagDataStore: ghostdagDataStore,
blockStatusStore: blockStatusStore,
blockRelationStore: blockRelationStore,
consensusStateStore: consensusStateStore,
headersSelectedTipStore: headersSelectedTipStore,
multisetStore: multisetStore,
reachabilityDataStore: reachabilityDataStore,
utxoDiffStore: utxoDiffStore,
finalityStore: finalityStore,
}
genesisInfo, err := c.GetBlockInfo(genesisHash)
@@ -333,7 +335,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
}
if !genesisInfo.Exists {
err = c.ValidateAndInsertBlock(dagParams.GenesisBlock)
_, err = c.ValidateAndInsertBlock(dagParams.GenesisBlock)
if err != nil {
return nil, err
}
@@ -343,7 +345,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
}
func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string) (
tc testapi.TestConsensus, teardown func(), err error) {
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) {
dataDir, err := ioutil.TempDir("", testName)
if err != nil {
@@ -354,7 +356,7 @@ func (f *factory) NewTestConsensus(dagParams *dagconfig.Params, testName string)
}
func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataDir string) (
tc testapi.TestConsensus, teardown func(), err error) {
tc testapi.TestConsensus, teardown func(keepDataDir bool), err error) {
db, err := ldb.NewLevelDB(dataDir)
if err != nil {
@@ -379,9 +381,14 @@ func (f *factory) NewTestConsensusWithDataDir(dagParams *dagconfig.Params, dataD
testTransactionValidator: testTransactionValidator,
}
tstConsensus.testBlockBuilder = blockbuilder.NewTestBlockBuilder(consensusAsImplementation.blockBuilder, tstConsensus)
teardown = func() {
teardown = func(keepDataDir bool) {
db.Close()
os.RemoveAll(dataDir)
if !keepDataDir {
err := os.RemoveAll(dataDir)
if err != nil {
log.Errorf("Error removing data directory for test consensus: %s", err)
}
}
}
return tstConsensus, teardown, nil

View File

@@ -24,7 +24,7 @@ func TestFinality(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
buildAndInsertBlock := func(parentHashes []*externalapi.DomainHash) (*externalapi.DomainBlock, error) {
block, _, err := consensus.BuildBlockWithParents(parentHashes, nil, nil)
@@ -32,7 +32,7 @@ func TestFinality(t *testing.T) {
return nil, err
}
err = consensus.ValidateAndInsertBlock(block)
_, err = consensus.ValidateAndInsertBlock(block)
if err != nil {
return nil, err
}
@@ -190,7 +190,7 @@ func TestBoundedMergeDepth(t *testing.T) {
return nil, false // fo some reason go doesn't recognize that t.Fatalf never returns
}
err = consensus.ValidateAndInsertBlock(block)
_, err = consensus.ValidateAndInsertBlock(block)
if err == nil {
return block, false
} else if errors.Is(err, ruleerrors.ErrViolatingBoundedMergeDepth) {
@@ -202,7 +202,7 @@ func TestBoundedMergeDepth(t *testing.T) {
}
processBlock := func(consensus testapi.TestConsensus, block *externalapi.DomainBlock, name string) {
err := consensus.ValidateAndInsertBlock(block)
_, err := consensus.ValidateAndInsertBlock(block)
if err != nil {
t.Fatalf("TestBoundedMergeDepth: %s got unexpected error from ProcessBlock: %+v", name, err)
@@ -214,7 +214,7 @@ func TestBoundedMergeDepth(t *testing.T) {
if err != nil {
t.Fatalf("TestBoundedMergeDepth: Failed building block: %v", err)
}
err = consensus.ValidateAndInsertBlock(block)
_, err = consensus.ValidateAndInsertBlock(block)
if err != nil {
t.Fatalf("TestBoundedMergeDepth: Failed Inserting block to consensus: %v", err)
}
@@ -241,7 +241,7 @@ func TestBoundedMergeDepth(t *testing.T) {
if err != nil {
t.Fatalf("TestBoundedMergeDepth: Error setting up consensus: %+v", err)
}
defer teardownFunc2()
defer teardownFunc2(false)
// Create a block on top on genesis
block1 := buildAndInsertBlock(consensusBuild, []*externalapi.DomainHash{params.GenesisHash})
@@ -266,7 +266,7 @@ func TestBoundedMergeDepth(t *testing.T) {
}
// Teardown and assign nil to make sure we use the right DAG from here on.
teardownFunc1()
teardownFunc1(false)
consensusBuild = nil
// Now test against the real DAG

7
domain/consensus/log.go Normal file
View File

@@ -0,0 +1,7 @@
package consensus
import (
"github.com/kaspanet/kaspad/infrastructure/logger"
)
var log, _ = logger.Get(logger.SubsystemTags.BDAG)

View File

@@ -5,6 +5,4 @@ type BlockInfo struct {
Exists bool
BlockStatus BlockStatus
BlueScore uint64
IsBlockInHeaderPruningPointFuture bool
}

View File

@@ -3,7 +3,7 @@ package externalapi
// Consensus maintains the current core state of the node
type Consensus interface {
BuildBlock(coinbaseData *DomainCoinbaseData, transactions []*DomainTransaction) (*DomainBlock, error)
ValidateAndInsertBlock(block *DomainBlock) error
ValidateAndInsertBlock(block *DomainBlock) (*BlockInsertionResult, error)
ValidateTransactionAndPopulateWithConsensusData(transaction *DomainTransaction) error
GetBlock(blockHash *DomainHash) (*DomainBlock, error)
@@ -13,7 +13,7 @@ type Consensus interface {
GetHashesBetween(lowHash, highHash *DomainHash) ([]*DomainHash, error)
GetMissingBlockBodyHashes(highHash *DomainHash) ([]*DomainHash, error)
GetPruningPointUTXOSet(expectedPruningPointHash *DomainHash) ([]byte, error)
SetPruningPointUTXOSet(serializedUTXOSet []byte) error
ValidateAndInsertPruningPoint(newPruningPoint *DomainBlock, serializedUTXOSet []byte) error
GetVirtualSelectedParent() (*DomainBlock, error)
CreateBlockLocator(lowHash, highHash *DomainHash, limit uint32) (BlockLocator, error)
FindNextBlockLocatorBoundaries(blockLocator BlockLocator) (lowHash, highHash *DomainHash, err error)

View File

@@ -0,0 +1,12 @@
package externalapi
// BlockInsertionResult is auxiliary data returned from ValidateAndInsertBlock
type BlockInsertionResult struct {
SelectedParentChainChanges *SelectedParentChainChanges
}
// SelectedParentChainChanges is the set of changes made to the selected parent chain
type SelectedParentChainChanges struct {
Added []*DomainHash
Removed []*DomainHash
}

View File

@@ -1,37 +1,8 @@
package externalapi
import "fmt"
// Each of the following represent one of the possible sync
// states of the consensus
const (
SyncStateSynced SyncState = iota
SyncStateAwaitingGenesis
SyncStateAwaitingUTXOSet
SyncStateAwaitingBlockBodies
)
// SyncState represents the current sync state of the consensus
type SyncState uint8
func (s SyncState) String() string {
switch s {
case SyncStateSynced:
return "SyncStateSynced"
case SyncStateAwaitingGenesis:
return "SyncStateAwaitingGenesis"
case SyncStateAwaitingUTXOSet:
return "SyncStateAwaitingUTXOSet"
case SyncStateAwaitingBlockBodies:
return "SyncStateAwaitingBlockBodies"
}
return fmt.Sprintf("<unknown state (%d)>", s)
}
// SyncInfo holds info about the current sync state of the consensus
type SyncInfo struct {
State SyncState
IsAwaitingUTXOSet bool
IBDRootUTXOBlockHash *DomainHash
HeaderCount uint64
BlockCount uint64

View File

@@ -2,11 +2,11 @@ package model
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// HeaderTipsStore represents a store of the header tips
type HeaderTipsStore interface {
// HeaderSelectedTipStore represents a store of the headers selected tip
type HeaderSelectedTipStore interface {
Store
Stage(tips []*externalapi.DomainHash)
Stage(selectedTip *externalapi.DomainHash)
IsStaged() bool
Tips(dbContext DBReader) ([]*externalapi.DomainHash, error)
HasTips(dbContext DBReader) (bool, error)
HeadersSelectedTip(dbContext DBReader) (*externalapi.DomainHash, error)
Has(dbContext DBReader) (bool, error)
}

View File

@@ -4,5 +4,6 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// BlockProcessor is responsible for processing incoming blocks
type BlockProcessor interface {
ValidateAndInsertBlock(block *externalapi.DomainBlock) error
ValidateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error)
ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error
}

View File

@@ -4,10 +4,9 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// ConsensusStateManager manages the node's consensus state
type ConsensusStateManager interface {
AddBlockToVirtual(blockHash *externalapi.DomainHash) error
AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error)
PopulateTransactionWithUTXOEntries(transaction *externalapi.DomainTransaction) error
SetPruningPointUTXOSet(serializedUTXOSet []byte) error
UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error
RestorePastUTXOSetIterator(blockHash *externalapi.DomainHash) (ReadOnlyUTXOSetIterator, error)
HeaderTipsPruningPoint() (*externalapi.DomainHash, error)
CalculatePastUTXOAndAcceptanceData(blockHash *externalapi.DomainHash) (UTXODiff, AcceptanceData, Multiset, error)
}

View File

@@ -4,7 +4,6 @@ import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// FinalityManager provides method to validate that a block does not violate finality
type FinalityManager interface {
IsViolatingFinality(blockHash *externalapi.DomainHash) (bool, error)
VirtualFinalityPoint() (*externalapi.DomainHash, error)
FinalityPoint(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error)
}

View File

@@ -2,8 +2,7 @@ package model
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// HeaderTipsManager manages the state of the header tips
type HeaderTipsManager interface {
// HeadersSelectedTipManager manages the state of the headers selected tip
type HeadersSelectedTipManager interface {
AddHeaderTip(hash *externalapi.DomainHash) error
SelectedTip() (*externalapi.DomainHash, error)
}

View File

@@ -1,6 +1,9 @@
package model
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
// PruningManager resolves and manages the current pruning point
type PruningManager interface {
FindNextPruningPoint() error
UpdatePruningPointByVirtual() error
CalculatePruningPointByHeaderSelectedTip() (*externalapi.DomainHash, error)
}

View File

@@ -8,6 +8,5 @@ type SyncManager interface {
GetMissingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error)
CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error)
FindNextBlockLocatorBoundaries(blockLocator externalapi.BlockLocator) (lowHash, highHash *externalapi.DomainHash, err error)
IsBlockInHeaderPruningPointFuture(blockHash *externalapi.DomainHash) (bool, error)
GetSyncInfo() (*externalapi.SyncInfo, error)
}

View File

@@ -11,7 +11,7 @@ type TestConsensus interface {
externalapi.Consensus
DAGParams() *dagconfig.Params
DatabaseContext() model.DBReader
DatabaseContext() model.DBManager
BuildBlockWithParents(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainBlock, model.UTXODiff, error)
@@ -19,7 +19,7 @@ type TestConsensus interface {
// AddBlock builds a block with given information, solves it, and adds to the DAG.
// Returns the hash of the added block
AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, error)
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, error)
DiscardAllStores()
@@ -30,7 +30,7 @@ type TestConsensus interface {
BlockStore() model.BlockStore
ConsensusStateStore() model.ConsensusStateStore
GHOSTDAGDataStore() model.GHOSTDAGDataStore
HeaderTipsStore() model.HeaderTipsStore
HeaderTipsStore() model.HeaderSelectedTipStore
MultisetStore() model.MultisetStore
PruningStore() model.PruningStore
ReachabilityDataStore() model.ReachabilityDataStore
@@ -46,7 +46,7 @@ type TestConsensus interface {
DAGTraversalManager() model.DAGTraversalManager
DifficultyManager() model.DifficultyManager
GHOSTDAGManager() model.GHOSTDAGManager
HeaderTipsManager() model.HeaderTipsManager
HeaderTipsManager() model.HeadersSelectedTipManager
MergeDepthManager() model.MergeDepthManager
PastMedianTimeManager() model.PastMedianTimeManager
PruningManager() model.PruningManager

View File

@@ -21,22 +21,22 @@ type blockProcessor struct {
ghostdagManager model.GHOSTDAGManager
pastMedianTimeManager model.PastMedianTimeManager
coinbaseManager model.CoinbaseManager
headerTipsManager model.HeaderTipsManager
headerTipsManager model.HeadersSelectedTipManager
syncManager model.SyncManager
acceptanceDataStore model.AcceptanceDataStore
blockStore model.BlockStore
blockStatusStore model.BlockStatusStore
blockRelationStore model.BlockRelationStore
multisetStore model.MultisetStore
ghostdagDataStore model.GHOSTDAGDataStore
consensusStateStore model.ConsensusStateStore
pruningStore model.PruningStore
reachabilityDataStore model.ReachabilityDataStore
utxoDiffStore model.UTXODiffStore
blockHeaderStore model.BlockHeaderStore
headerTipsStore model.HeaderTipsStore
finalityStore model.FinalityStore
acceptanceDataStore model.AcceptanceDataStore
blockStore model.BlockStore
blockStatusStore model.BlockStatusStore
blockRelationStore model.BlockRelationStore
multisetStore model.MultisetStore
ghostdagDataStore model.GHOSTDAGDataStore
consensusStateStore model.ConsensusStateStore
pruningStore model.PruningStore
reachabilityDataStore model.ReachabilityDataStore
utxoDiffStore model.UTXODiffStore
blockHeaderStore model.BlockHeaderStore
headersSelectedTipStore model.HeaderSelectedTipStore
finalityStore model.FinalityStore
stores []model.Store
}
@@ -54,7 +54,7 @@ func New(
pastMedianTimeManager model.PastMedianTimeManager,
ghostdagManager model.GHOSTDAGManager,
coinbaseManager model.CoinbaseManager,
headerTipsManager model.HeaderTipsManager,
headerTipsManager model.HeadersSelectedTipManager,
syncManager model.SyncManager,
acceptanceDataStore model.AcceptanceDataStore,
@@ -68,7 +68,7 @@ func New(
reachabilityDataStore model.ReachabilityDataStore,
utxoDiffStore model.UTXODiffStore,
blockHeaderStore model.BlockHeaderStore,
headerTipsStore model.HeaderTipsStore,
headersSelectedTipStore model.HeaderSelectedTipStore,
finalityStore model.FinalityStore,
) model.BlockProcessor {
@@ -86,20 +86,20 @@ func New(
headerTipsManager: headerTipsManager,
syncManager: syncManager,
consensusStateManager: consensusStateManager,
acceptanceDataStore: acceptanceDataStore,
blockStore: blockStore,
blockStatusStore: blockStatusStore,
blockRelationStore: blockRelationStore,
multisetStore: multisetStore,
ghostdagDataStore: ghostdagDataStore,
consensusStateStore: consensusStateStore,
pruningStore: pruningStore,
reachabilityDataStore: reachabilityDataStore,
utxoDiffStore: utxoDiffStore,
blockHeaderStore: blockHeaderStore,
headerTipsStore: headerTipsStore,
finalityStore: finalityStore,
consensusStateManager: consensusStateManager,
acceptanceDataStore: acceptanceDataStore,
blockStore: blockStore,
blockStatusStore: blockStatusStore,
blockRelationStore: blockRelationStore,
multisetStore: multisetStore,
ghostdagDataStore: ghostdagDataStore,
consensusStateStore: consensusStateStore,
pruningStore: pruningStore,
reachabilityDataStore: reachabilityDataStore,
utxoDiffStore: utxoDiffStore,
blockHeaderStore: blockHeaderStore,
headersSelectedTipStore: headersSelectedTipStore,
finalityStore: finalityStore,
stores: []model.Store{
consensusStateStore,
@@ -114,7 +114,7 @@ func New(
reachabilityDataStore,
utxoDiffStore,
blockHeaderStore,
headerTipsStore,
headersSelectedTipStore,
finalityStore,
},
}
@@ -122,9 +122,16 @@ func New(
// ValidateAndInsertBlock validates the given block and, if valid, applies it
// to the current state
func (bp *blockProcessor) ValidateAndInsertBlock(block *externalapi.DomainBlock) error {
func (bp *blockProcessor) ValidateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateAndInsertBlock")
defer onEnd()
return bp.validateAndInsertBlock(block)
}
func (bp *blockProcessor) ValidateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateAndInsertPruningPoint")
defer onEnd()
return bp.validateAndInsertPruningPoint(newPruningPoint, serializedUTXOSet)
}

View File

@@ -11,36 +11,16 @@ import (
"github.com/pkg/errors"
)
type insertMode uint8
const (
insertModeGenesis insertMode = iota
insertModeHeader
insertModeBlockBody
insertModeBlock
)
func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) error {
func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock) (*externalapi.BlockInsertionResult, error) {
blockHash := consensushashing.HeaderHash(block.Header)
log.Debugf("Validating block %s", blockHash)
insertMode, err := bp.validateAgainstSyncStateAndResolveInsertMode(block)
if err != nil {
return err
}
err = bp.checkBlockStatus(blockHash, insertMode)
if err != nil {
return err
}
err = bp.validateBlock(block, insertMode)
err := bp.validateBlock(block)
if err != nil {
bp.discardAllChanges()
return err
return nil, err
}
if insertMode == insertModeHeader {
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
if isHeaderOnlyBlock {
bp.blockStatusStore.Stage(blockHash, externalapi.StatusHeaderOnly)
} else {
bp.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification)
@@ -50,55 +30,51 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
// collected so far
err = bp.commitAllChanges()
if err != nil {
return err
return nil, err
}
var oldHeadersSelectedTip *externalapi.DomainHash
if insertMode != insertModeGenesis {
isGenesis := *blockHash != *bp.genesisHash
if isGenesis {
var err error
oldHeadersSelectedTip, err = bp.headerTipsManager.SelectedTip()
oldHeadersSelectedTip, err = bp.headersSelectedTipStore.HeadersSelectedTip(bp.databaseContext)
if err != nil {
return err
return nil, err
}
}
if insertMode == insertModeHeader {
err = bp.headerTipsManager.AddHeaderTip(blockHash)
if err != nil {
return err
}
} else if insertMode == insertModeBlock || insertMode == insertModeGenesis {
err = bp.headerTipsManager.AddHeaderTip(blockHash)
if err != nil {
return nil, err
}
var selectedParentChainChanges *externalapi.SelectedParentChainChanges
if !isHeaderOnlyBlock {
// Attempt to add the block to the virtual
err = bp.consensusStateManager.AddBlockToVirtual(blockHash)
selectedParentChainChanges, err = bp.consensusStateManager.AddBlock(blockHash)
if err != nil {
return err
return nil, err
}
tips, err := bp.consensusStateStore.Tips(bp.databaseContext)
if err != nil {
return err
}
bp.headerTipsStore.Stage(tips)
}
if insertMode != insertModeGenesis {
if isGenesis {
err := bp.updateReachabilityReindexRoot(oldHeadersSelectedTip)
if err != nil {
return err
return nil, err
}
}
if insertMode == insertModeBlock {
if !isHeaderOnlyBlock {
// Trigger pruning, which will check if the pruning point changed and delete the data if it did.
err = bp.pruningManager.FindNextPruningPoint()
err = bp.pruningManager.UpdatePruningPointByVirtual()
if err != nil {
return err
return nil, err
}
}
err = bp.commitAllChanges()
if err != nil {
return err
return nil, err
}
log.Debugf("Block %s validated and inserted", blockHash)
@@ -110,71 +86,18 @@ func (bp *blockProcessor) validateAndInsertBlock(block *externalapi.DomainBlock)
logClosureErr = err
return fmt.Sprintf("Failed to get virtual GHOSTDAG data: %s", err)
}
syncInfo, err := bp.syncManager.GetSyncInfo()
if err != nil {
logClosureErr = err
return fmt.Sprintf("Failed to get sync info: %s", err)
}
return fmt.Sprintf("New virtual's blue score: %d. Sync state: %s. Block count: %d. Header count: %d",
virtualGhostDAGData.BlueScore(), syncInfo.State, syncInfo.BlockCount, syncInfo.HeaderCount)
headerCount := bp.blockHeaderStore.Count()
blockCount := bp.blockStore.Count()
return fmt.Sprintf("New virtual's blue score: %d. Block count: %d. Header count: %d",
virtualGhostDAGData.BlueScore(), blockCount, headerCount)
}))
if logClosureErr != nil {
return logClosureErr
return nil, logClosureErr
}
return nil
}
func (bp *blockProcessor) validateAgainstSyncStateAndResolveInsertMode(block *externalapi.DomainBlock) (insertMode, error) {
syncInfo, err := bp.syncManager.GetSyncInfo()
if err != nil {
return 0, err
}
syncState := syncInfo.State
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
blockHash := consensushashing.HeaderHash(block.Header)
if syncState == externalapi.SyncStateAwaitingGenesis {
if isHeaderOnlyBlock {
return 0, errors.Errorf("Got a header-only block while awaiting genesis")
}
if *blockHash != *bp.genesisHash {
return 0, errors.Errorf("Received a non-genesis block while awaiting genesis")
}
return insertModeGenesis, nil
}
if isHeaderOnlyBlock {
return insertModeHeader, nil
}
if syncState == externalapi.SyncStateAwaitingUTXOSet {
headerTipsPruningPoint, err := bp.consensusStateManager.HeaderTipsPruningPoint()
if err != nil {
return 0, err
}
if *blockHash != *headerTipsPruningPoint {
return 0, errors.Errorf("cannot insert blocks other than the header pruning point " +
"while awaiting the UTXO set")
}
return insertModeBlock, nil
}
if syncState == externalapi.SyncStateAwaitingBlockBodies {
headerTips, err := bp.headerTipsStore.Tips(bp.databaseContext)
if err != nil {
return 0, err
}
selectedHeaderTip, err := bp.ghostdagManager.ChooseSelectedParent(headerTips...)
if err != nil {
return 0, err
}
if *selectedHeaderTip != *blockHash {
return insertModeBlockBody, nil
}
}
return insertModeBlock, nil
return &externalapi.BlockInsertionResult{
SelectedParentChainChanges: selectedParentChainChanges,
}, nil
}
func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool {
@@ -182,7 +105,7 @@ func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool {
}
func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *externalapi.DomainHash) error {
headersSelectedTip, err := bp.headerTipsManager.SelectedTip()
headersSelectedTip, err := bp.headersSelectedTipStore.HeadersSelectedTip(bp.databaseContext)
if err != nil {
return err
}
@@ -194,7 +117,9 @@ func (bp *blockProcessor) updateReachabilityReindexRoot(oldHeadersSelectedTip *e
return bp.reachabilityManager.UpdateReindexRoot(headersSelectedTip)
}
func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode insertMode) error {
func (bp *blockProcessor) checkBlockStatus(block *externalapi.DomainBlock) error {
hash := consensushashing.BlockHash(block)
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
exists, err := bp.blockStatusStore.Exists(bp.databaseContext, hash)
if err != nil {
return err
@@ -212,12 +137,12 @@ func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode in
return errors.Wrapf(ruleerrors.ErrKnownInvalid, "block %s is a known invalid block", hash)
}
isBlockBodyAfterBlockHeader := mode != insertModeHeader && status == externalapi.StatusHeaderOnly
isBlockBodyAfterBlockHeader := !isHeaderOnlyBlock && status == externalapi.StatusHeaderOnly
if !isBlockBodyAfterBlockHeader {
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash)
}
isDuplicateHeader := mode == insertModeHeader && status == externalapi.StatusHeaderOnly
isDuplicateHeader := isHeaderOnlyBlock && status == externalapi.StatusHeaderOnly
if isDuplicateHeader {
return errors.Wrapf(ruleerrors.ErrDuplicateBlock, "block %s already exists", hash)
}
@@ -225,57 +150,16 @@ func (bp *blockProcessor) checkBlockStatus(hash *externalapi.DomainHash, mode in
return nil
}
func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock, mode insertMode) error {
blockHash := consensushashing.HeaderHash(block.Header)
hasHeader, err := bp.hasHeader(blockHash)
if err != nil {
return err
}
if !hasHeader {
bp.blockHeaderStore.Stage(blockHash, block.Header)
}
// If any validation until (included) proof-of-work fails, simply
// return an error without writing anything in the database.
// This is to prevent spamming attacks.
err = bp.validatePreProofOfWork(block)
if err != nil {
return err
}
err = bp.validatePruningPointViolationAndProofOfWorkAndDifficulty(block, mode)
if err != nil {
return err
}
// If in-context validations fail, discard all changes and store the
// block with StatusInvalid.
err = bp.validatePostProofOfWork(block, mode)
if err != nil {
if errors.As(err, &ruleerrors.RuleError{}) {
bp.discardAllChanges()
hash := consensushashing.BlockHash(block)
bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid)
commitErr := bp.commitAllChanges()
if commitErr != nil {
return commitErr
}
}
return err
}
return nil
}
func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock) error {
blockHash := consensushashing.BlockHash(block)
hasHeader, err := bp.hasHeader(blockHash)
hasValidatedOnlyHeader, err := bp.hasValidatedOnlyHeader(blockHash)
if err != nil {
return err
}
if hasHeader {
if hasValidatedOnlyHeader {
log.Debugf("Block %s header was already validated, so skip the rest of validatePreProofOfWork", blockHash)
return nil
}
@@ -286,41 +170,43 @@ func (bp *blockProcessor) validatePreProofOfWork(block *externalapi.DomainBlock)
return nil
}
func (bp *blockProcessor) validatePruningPointViolationAndProofOfWorkAndDifficulty(block *externalapi.DomainBlock, mode insertMode) error {
blockHash := consensushashing.HeaderHash(block.Header)
if mode != insertModeHeader {
// We stage the block here since we need it for parent validation
bp.blockStore.Stage(blockHash, block)
}
return bp.blockValidator.ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash)
}
func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock, mode insertMode) error {
func (bp *blockProcessor) validatePostProofOfWork(block *externalapi.DomainBlock) error {
blockHash := consensushashing.BlockHash(block)
if mode != insertModeHeader {
isHeaderOnlyBlock := isHeaderOnlyBlock(block)
if !isHeaderOnlyBlock {
bp.blockStore.Stage(blockHash, block)
err := bp.blockValidator.ValidateBodyInIsolation(blockHash)
if err != nil {
return err
}
}
hasHeader, err := bp.hasHeader(blockHash)
hasValidatedHeader, err := bp.hasValidatedOnlyHeader(blockHash)
if err != nil {
return err
}
if !hasHeader {
if !hasValidatedHeader {
err = bp.blockValidator.ValidateHeaderInContext(blockHash)
if err != nil {
return err
}
}
if !isHeaderOnlyBlock {
err = bp.blockValidator.ValidateBodyInContext(blockHash)
if err != nil {
return err
}
} else {
log.Tracef("Skipping ValidateBodyInContext for block %s because it's header only", blockHash)
}
return nil
}
func (bp *blockProcessor) hasHeader(blockHash *externalapi.DomainHash) (bool, error) {
func (bp *blockProcessor) hasValidatedOnlyHeader(blockHash *externalapi.DomainHash) (bool, error) {
exists, err := bp.blockStatusStore.Exists(bp.databaseContext, blockHash)
if err != nil {
return false, err

View File

@@ -0,0 +1,39 @@
package blockprocessor
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/pkg/errors"
)
func (bp *blockProcessor) validateAndInsertPruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
log.Info("Checking that the given pruning point is the expected pruning point")
expectedNewPruningPointHash, err := bp.pruningManager.CalculatePruningPointByHeaderSelectedTip()
if err != nil {
return err
}
newPruningPointHash := consensushashing.BlockHash(newPruningPoint)
if *expectedNewPruningPointHash != *newPruningPointHash {
return errors.Wrapf(ruleerrors.ErrUnexpectedPruningPoint, "expected pruning point %s but got %s",
expectedNewPruningPointHash, newPruningPointHash)
}
// We have to validate the pruning point block before we set the new pruning point in consensusStateManager.
log.Infof("Validating the new pruning point %s", newPruningPointHash)
err = bp.validateBlockAndDiscardChanges(newPruningPoint)
if err != nil {
return err
}
err = bp.consensusStateManager.UpdatePruningPoint(newPruningPoint, serializedUTXOSet)
if err != nil {
return err
}
_, err = bp.ValidateAndInsertBlock(newPruningPoint)
return err
}

View File

@@ -0,0 +1,67 @@
package blockprocessor
import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/pkg/errors"
)
func (bp *blockProcessor) validateBlockAndDiscardChanges(block *externalapi.DomainBlock) error {
defer bp.discardAllChanges()
return bp.validateBlock(block)
}
func (bp *blockProcessor) validateBlock(block *externalapi.DomainBlock) error {
blockHash := consensushashing.HeaderHash(block.Header)
log.Debugf("Validating block %s", blockHash)
err := bp.checkBlockStatus(block)
if err != nil {
return err
}
hasValidatedHeader, err := bp.hasValidatedOnlyHeader(blockHash)
if err != nil {
return err
}
if !hasValidatedHeader {
log.Tracef("Staging block %s header", blockHash)
bp.blockHeaderStore.Stage(blockHash, block.Header)
} else {
log.Tracef("Block %s header is already known, so no need to stage it", blockHash)
}
// If any validation until (included) proof-of-work fails, simply
// return an error without writing anything in the database.
// This is to prevent spamming attacks.
err = bp.validatePreProofOfWork(block)
if err != nil {
return err
}
if !hasValidatedHeader {
err = bp.blockValidator.ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash)
if err != nil {
return err
}
}
// If in-context validations fail, discard all changes and store the
// block with StatusInvalid.
err = bp.validatePostProofOfWork(block)
if err != nil {
if errors.As(err, &ruleerrors.RuleError{}) {
bp.discardAllChanges()
hash := consensushashing.BlockHash(block)
bp.blockStatusStore.Stage(hash, externalapi.StatusInvalid)
commitErr := bp.commitAllChanges()
if commitErr != nil {
return commitErr
}
}
return err
}
return nil
}

View File

@@ -1,6 +1,7 @@
package blockvalidator
import (
"github.com/kaspanet/kaspad/infrastructure/logger"
"math"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
@@ -13,6 +14,9 @@ import (
// ValidateBodyInContext validates block bodies in the context of the current
// consensus state
func (v *blockValidator) ValidateBodyInContext(blockHash *externalapi.DomainHash) error {
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateBodyInContext")
defer onEnd()
return v.checkBlockTransactionsFinalized(blockHash)
}

View File

@@ -8,12 +8,16 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/utils/merkle"
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/pkg/errors"
)
// ValidateBodyInIsolation validates block bodies in isolation from the current
// consensus state
func (v *blockValidator) ValidateBodyInIsolation(blockHash *externalapi.DomainHash) error {
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateBodyInContext")
defer onEnd()
block, err := v.blockStore.Block(v.databaseContext, blockHash)
if err != nil {
return err

View File

@@ -24,9 +24,9 @@ func TestChainedTransactions(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
block1Hash, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
block1Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -47,13 +47,13 @@ func TestChainedTransactions(t *testing.T) {
}
// Check that a block is invalid if it contains chained transactions
_, err = tc.AddBlock([]*externalapi.DomainHash{block1Hash}, nil,
_, _, err = tc.AddBlock([]*externalapi.DomainHash{block1Hash}, nil,
[]*externalapi.DomainTransaction{tx1, chainedTx})
if !errors.Is(err, ruleerrors.ErrChainedTransactions) {
t.Fatalf("unexpected error %+v", err)
}
block2Hash, err := tc.AddBlock([]*externalapi.DomainHash{block1Hash}, nil, nil)
block2Hash, _, err := tc.AddBlock([]*externalapi.DomainHash{block1Hash}, nil, nil)
if err != nil {
t.Fatalf("unexpected error %+v", err)
}
@@ -69,7 +69,7 @@ func TestChainedTransactions(t *testing.T) {
}
// Check that a block is valid if it contains two non chained transactions
_, err = tc.AddBlock([]*externalapi.DomainHash{block2Hash}, nil,
_, _, err = tc.AddBlock([]*externalapi.DomainHash{block2Hash}, nil,
[]*externalapi.DomainTransaction{tx1, tx2})
if err != nil {
t.Fatalf("unexpected error %+v", err)
@@ -86,7 +86,7 @@ func TestCheckBlockSanity(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
blockHash := consensushashing.BlockHash(&exampleValidBlock)
if len(exampleValidBlock.Transactions) < 3 {
t.Fatalf("Too few transactions in block, expect at least 3, got %v", len(exampleValidBlock.Transactions))

View File

@@ -4,23 +4,27 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/pkg/errors"
)
// ValidateHeaderInContext validates block headers in the context of the current
// consensus state
func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHash) error {
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateHeaderInContext")
defer onEnd()
header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash)
if err != nil {
return err
}
isHeadersOnlyBlock, err := v.isHeadersOnlyBlock(blockHash)
hasValidatedHeader, err := v.hasValidatedHeader(blockHash)
if err != nil {
return err
}
if !isHeadersOnlyBlock {
if !hasValidatedHeader {
err = v.ghostdagManager.GHOSTDAG(blockHash)
if err != nil {
return err
@@ -60,7 +64,7 @@ func (v *blockValidator) ValidateHeaderInContext(blockHash *externalapi.DomainHa
return nil
}
func (v *blockValidator) isHeadersOnlyBlock(blockHash *externalapi.DomainHash) (bool, error) {
func (v *blockValidator) hasValidatedHeader(blockHash *externalapi.DomainHash) (bool, error) {
exists, err := v.blockStatusStore.Exists(v.databaseContext, blockHash)
if err != nil {
return false, err

View File

@@ -20,7 +20,7 @@ func TestValidateMedianTime(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
addBlock := func(blockTime int64, parents []*externalapi.DomainHash, expectedErr error) (*externalapi.DomainBlock, *externalapi.DomainHash) {
block, _, err := tc.BuildBlockWithParents(parents, nil, nil)
@@ -29,7 +29,7 @@ func TestValidateMedianTime(t *testing.T) {
}
block.Header.TimeInMilliseconds = blockTime
err = tc.ValidateAndInsertBlock(block)
_, err = tc.ValidateAndInsertBlock(block)
if !errors.Is(err, expectedErr) {
t.Fatalf("expected error %s but got %+v", expectedErr, err)
}
@@ -87,19 +87,19 @@ func TestCheckParentsIncest(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
a, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
a, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
b, err := tc.AddBlock([]*externalapi.DomainHash{a}, nil, nil)
b, _, err := tc.AddBlock([]*externalapi.DomainHash{a}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
c, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
c, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -118,7 +118,7 @@ func TestCheckParentsIncest(t *testing.T) {
Transactions: nil,
}
err = tc.ValidateAndInsertBlock(directParentsRelationBlock)
_, err = tc.ValidateAndInsertBlock(directParentsRelationBlock)
if !errors.Is(err, ruleerrors.ErrInvalidParentsRelation) {
t.Fatalf("unexpected error %+v", err)
}
@@ -137,13 +137,13 @@ func TestCheckParentsIncest(t *testing.T) {
Transactions: nil,
}
err = tc.ValidateAndInsertBlock(indirectParentsRelationBlock)
_, err = tc.ValidateAndInsertBlock(indirectParentsRelationBlock)
if !errors.Is(err, ruleerrors.ErrInvalidParentsRelation) {
t.Fatalf("unexpected error %+v", err)
}
// Try to add block with unrelated parents
_, err = tc.AddBlock([]*externalapi.DomainHash{b, c}, nil, nil)
_, _, err = tc.AddBlock([]*externalapi.DomainHash{b, c}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %s", err)
}

View File

@@ -4,6 +4,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/kaspanet/kaspad/util/mstime"
"github.com/pkg/errors"
)
@@ -11,6 +12,9 @@ import (
// ValidateHeaderInIsolation validates block headers in isolation from the current
// consensus state
func (v *blockValidator) ValidateHeaderInIsolation(blockHash *externalapi.DomainHash) error {
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidateHeaderInIsolation")
defer onEnd()
header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash)
if err != nil {
return err

View File

@@ -0,0 +1,7 @@
package blockvalidator
import (
"github.com/kaspanet/kaspad/infrastructure/logger"
)
var log, _ = logger.Get(logger.SubsystemTags.BLVL)

View File

@@ -5,11 +5,15 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/pow"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/infrastructure/logger"
"github.com/kaspanet/kaspad/util"
"github.com/pkg/errors"
)
func (v *blockValidator) ValidatePruningPointViolationAndProofOfWorkAndDifficulty(blockHash *externalapi.DomainHash) error {
onEnd := logger.LogAndMeasureExecutionTime(log, "ValidatePruningPointViolationAndProofOfWorkAndDifficulty")
defer onEnd()
header, err := v.blockHeaderStore.BlockHeader(v.databaseContext, blockHash)
if err != nil {
return err
@@ -93,7 +97,7 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader)
if !v.skipPoW {
valid := pow.CheckProofOfWorkWithTarget(header, target)
if !valid {
return errors.Wrap(ruleerrors.ErrUnexpectedDifficulty, "block has invalid difficulty")
return errors.Wrap(ruleerrors.ErrInvalidPoW, "block has invalid proof of work")
}
}
return nil
@@ -102,7 +106,7 @@ func (v *blockValidator) checkProofOfWork(header *externalapi.DomainBlockHeader)
func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, header *externalapi.DomainBlockHeader) error {
missingParentHashes := []*externalapi.DomainHash{}
isFullBlock, err := v.blockStore.HasBlock(v.databaseContext, blockHash)
hasBlockBody, err := v.blockStore.HasBlock(v.databaseContext, blockHash)
if err != nil {
return err
}
@@ -117,12 +121,31 @@ func (v *blockValidator) checkParentsExist(blockHash *externalapi.DomainHash, he
continue
}
if isFullBlock {
parentStatus, err := v.blockStatusStore.Get(v.databaseContext, parent)
if err != nil {
return err
}
parentStatus, err := v.blockStatusStore.Get(v.databaseContext, parent)
if err != nil {
return err
}
if parentStatus == externalapi.StatusInvalid {
return errors.Wrapf(ruleerrors.ErrInvalidAncestorBlock, "parent %s is invalid", parent)
}
if hasBlockBody {
if parentStatus == externalapi.StatusHeaderOnly {
pruningPoint, err := v.pruningStore.PruningPoint(v.databaseContext)
if err != nil {
return err
}
isInPastOfPruningPoint, err := v.dagTopologyManager.IsAncestorOf(parent, pruningPoint)
if err != nil {
return err
}
if isInPastOfPruningPoint {
continue
}
missingParentHashes = append(missingParentHashes, parent)
}
}

View File

@@ -18,7 +18,7 @@ type coinbaseManager struct {
acceptanceDataStore model.AcceptanceDataStore
}
func (c coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.DomainHash,
func (c *coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.DomainHash,
coinbaseData *externalapi.DomainCoinbaseData) (*externalapi.DomainTransaction, error) {
ghostdagData, err := c.ghostdagDataStore.Get(c.databaseContext, blockHash)
@@ -64,7 +64,7 @@ func (c coinbaseManager) ExpectedCoinbaseTransaction(blockHash *externalapi.Doma
// coinbaseOutputForBlueBlock calculates the output that should go into the coinbase transaction of blueBlock
// If blueBlock gets no fee - returns nil for txOut
func (c coinbaseManager) coinbaseOutputForBlueBlock(blueBlock *externalapi.DomainHash,
func (c *coinbaseManager) coinbaseOutputForBlueBlock(blueBlock *externalapi.DomainHash,
blockAcceptanceData *model.BlockAcceptanceData) (*externalapi.DomainTransactionOutput, bool, error) {
totalFees := uint64(0)
@@ -109,7 +109,7 @@ func (c coinbaseManager) coinbaseOutputForBlueBlock(blueBlock *externalapi.Domai
//
// At the target block generation rate for the main network, this is
// approximately every 4 years.
func (c coinbaseManager) calcBlockSubsidy(blockHash *externalapi.DomainHash) (uint64, error) {
func (c *coinbaseManager) calcBlockSubsidy(blockHash *externalapi.DomainHash) (uint64, error) {
if c.subsidyReductionInterval == 0 {
return c.baseSubsidy, nil
}

View File

@@ -15,7 +15,7 @@ const uint64Len = 8
const lengthOfscriptPubKeyLength = 1
// serializeCoinbasePayload builds the coinbase payload based on the provided scriptPubKey and extra data.
func (c coinbaseManager) serializeCoinbasePayload(blueScore uint64, coinbaseData *externalapi.DomainCoinbaseData) ([]byte, error) {
func (c *coinbaseManager) serializeCoinbasePayload(blueScore uint64, coinbaseData *externalapi.DomainCoinbaseData) ([]byte, error) {
scriptPubKeyLength := len(coinbaseData.ScriptPublicKey)
if uint64(scriptPubKeyLength) > c.coinbasePayloadScriptPublicKeyMaxLength {
return nil, errors.Wrapf(ruleerrors.ErrBadCoinbasePayloadLen, "coinbase's payload script public key is "+
@@ -34,7 +34,7 @@ func (c coinbaseManager) serializeCoinbasePayload(blueScore uint64, coinbaseData
}
// ExtractCoinbaseDataAndBlueScore deserializes the coinbase payload to its component (scriptPubKey and extra data).
func (c coinbaseManager) ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalapi.DomainTransaction) (blueScore uint64,
func (c *coinbaseManager) ExtractCoinbaseDataAndBlueScore(coinbaseTx *externalapi.DomainTransaction) (blueScore uint64,
coinbaseData *externalapi.DomainCoinbaseData, err error) {
minLength := uint64Len + lengthOfscriptPubKeyLength

View File

@@ -8,41 +8,41 @@ import (
// AddBlockToVirtual submits the given block to be added to the
// current virtual. This process may result in a new virtual block
// getting created
func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.DomainHash) error {
log.Tracef("AddBlockToVirtual start for block %s", blockHash)
defer log.Tracef("AddBlockToVirtual end for block %s", blockHash)
func (csm *consensusStateManager) AddBlock(blockHash *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) {
log.Tracef("AddBlock start for block %s", blockHash)
defer log.Tracef("AddBlock end for block %s", blockHash)
log.Tracef("Resolving whether the block %s is the next virtual selected parent", blockHash)
isNextVirtualSelectedParent, err := csm.isNextVirtualSelectedParent(blockHash)
isCandidateToBeNextVirtualSelectedParent, err := csm.isCandidateToBeNextVirtualSelectedParent(blockHash)
if err != nil {
return err
return nil, err
}
if isNextVirtualSelectedParent {
log.Tracef("Block %s is the new virtual. Resolving its block status", blockHash)
blockStatus, err := csm.resolveBlockStatus(blockHash)
if isCandidateToBeNextVirtualSelectedParent {
// It's important to check for finality violation before resolving the block status, because the status of
// blocks with a selected chain that doesn't contain the pruning point cannot be resolved because they will
// eventually try to fetch UTXO diffs from the past of the pruning point.
log.Tracef("Block %s is candidate to be the next virtual selected parent. Resolving whether it violates "+
"finality", blockHash)
isViolatingFinality, shouldNotify, err := csm.isViolatingFinality(blockHash)
if err != nil {
return err
return nil, err
}
if blockStatus == externalapi.StatusValid {
log.Tracef("Block %s is tentatively valid. Resolving whether it violates finality", blockHash)
err = csm.checkFinalityViolation(blockHash)
if err != nil {
return err
}
// Re-fetch the block status for logging purposes
// because it could've been changed in
// checkFinalityViolation
blockStatus, err = csm.blockStatusStore.Get(csm.databaseContext, blockHash)
if err != nil {
return err
}
if shouldNotify {
//TODO: Send finality conflict notification
log.Warnf("Finality Violation Detected! Block %s violates finality!", blockHash)
}
log.Debugf("Block %s is the next virtual selected parent. "+
"Its resolved status is `%s`", blockHash, blockStatus)
if !isViolatingFinality {
log.Tracef("Block %s doesn't violate finality. Resolving its block status", blockHash)
blockStatus, err := csm.resolveBlockStatus(blockHash)
if err != nil {
return nil, err
}
log.Debugf("Block %s resolved to status `%s`", blockHash, blockStatus)
}
} else {
log.Debugf("Block %s is not the next virtual selected parent, "+
"therefore its status remains `%s`", blockHash, externalapi.StatusUTXOPendingVerification)
@@ -51,22 +51,22 @@ func (csm *consensusStateManager) AddBlockToVirtual(blockHash *externalapi.Domai
log.Tracef("Adding block %s to the DAG tips", blockHash)
newTips, err := csm.addTip(blockHash)
if err != nil {
return err
return nil, err
}
log.Tracef("After adding %s, the new tips are %s", blockHash, newTips)
log.Tracef("Updating the virtual with the new tips")
err = csm.updateVirtual(blockHash, newTips)
selectedParentChainChanges, err := csm.updateVirtual(blockHash, newTips)
if err != nil {
return err
return nil, err
}
return nil
return selectedParentChainChanges, nil
}
func (csm *consensusStateManager) isNextVirtualSelectedParent(blockHash *externalapi.DomainHash) (bool, error) {
log.Tracef("isNextVirtualSelectedParent start for block %s", blockHash)
defer log.Tracef("isNextVirtualSelectedParent end for block %s", blockHash)
func (csm *consensusStateManager) isCandidateToBeNextVirtualSelectedParent(blockHash *externalapi.DomainHash) (bool, error) {
log.Tracef("isCandidateToBeNextVirtualSelectedParent start for block %s", blockHash)
defer log.Tracef("isCandidateToBeNextVirtualSelectedParent end for block %s", blockHash)
if *blockHash == *csm.genesisHash {
log.Tracef("Block %s is the genesis block, therefore it is "+

View File

@@ -23,7 +23,7 @@ func TestUTXOCommitment(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
// Build the following DAG:
// G <- A <- B <- C <- E
@@ -32,13 +32,13 @@ func TestUTXOCommitment(t *testing.T) {
genesisHash := params.GenesisHash
// Block A:
blockAHash, err := consensus.AddBlock([]*externalapi.DomainHash{genesisHash}, nil, nil)
blockAHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{genesisHash}, nil, nil)
if err != nil {
t.Fatalf("Error creating block A: %+v", err)
}
checkBlockUTXOCommitment(t, consensus, blockAHash, "A")
// Block B:
blockBHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockAHash}, nil, nil)
blockBHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{blockAHash}, nil, nil)
if err != nil {
t.Fatalf("Error creating block B: %+v", err)
}
@@ -48,7 +48,7 @@ func TestUTXOCommitment(t *testing.T) {
}
checkBlockUTXOCommitment(t, consensus, blockBHash, "B")
// Block C:
blockCHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash}, nil, nil)
blockCHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash}, nil, nil)
if err != nil {
t.Fatalf("Error creating block C: %+v", err)
}
@@ -59,14 +59,14 @@ func TestUTXOCommitment(t *testing.T) {
if err != nil {
t.Fatalf("Error creating transaction: %+v", err)
}
blockDHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash}, nil,
blockDHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{blockBHash}, nil,
[]*externalapi.DomainTransaction{blockDTransaction})
if err != nil {
t.Fatalf("Error creating block D: %+v", err)
}
checkBlockUTXOCommitment(t, consensus, blockDHash, "D")
// Block E:
blockEHash, err := consensus.AddBlock([]*externalapi.DomainHash{blockCHash, blockDHash}, nil, nil)
blockEHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{blockCHash, blockDHash}, nil, nil)
if err != nil {
t.Fatalf("Error creating block E: %+v", err)
}
@@ -119,12 +119,12 @@ func TestPastUTXOMultiset(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
// Build a short chain
currentHash := params.GenesisHash
for i := 0; i < 3; i++ {
currentHash, err = consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
currentHash, _, err = consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
if err != nil {
t.Fatalf("Error creating block A: %+v", err)
}
@@ -141,7 +141,7 @@ func TestPastUTXOMultiset(t *testing.T) {
firstMultisetHash := firstMultiset.Hash()
// Add another block on top of testedBlock
_, err = consensus.AddBlock([]*externalapi.DomainHash{testedBlockHash}, nil, nil)
_, _, err = consensus.AddBlock([]*externalapi.DomainHash{testedBlockHash}, nil, nil)
if err != nil {
t.Fatalf("Error creating block A: %+v", err)
}

View File

@@ -2,23 +2,65 @@ package consensusstatemanager
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
func (csm *consensusStateManager) checkFinalityViolation(
blockHash *externalapi.DomainHash) error {
func (csm *consensusStateManager) isViolatingFinality(blockHash *externalapi.DomainHash) (isViolatingFinality bool,
shouldSendNotification bool, err error) {
log.Tracef("checkFinalityViolation start for block %s", blockHash)
defer log.Tracef("checkFinalityViolation end for block %s", blockHash)
log.Tracef("isViolatingFinality start for block %s", blockHash)
defer log.Tracef("isViolatingFinality end for block %s", blockHash)
isViolatingFinality, err := csm.finalityManager.IsViolatingFinality(blockHash)
if err != nil {
return err
if *blockHash == *csm.genesisHash {
log.Tracef("Block %s is the genesis block, "+
"and does not violate finality by definition", blockHash)
return false, false, nil
}
if isViolatingFinality {
csm.blockStatusStore.Stage(blockHash, externalapi.StatusUTXOPendingVerification)
log.Warnf("Finality Violation Detected! Block %s violates finality!", blockHash)
return nil
var finalityPoint *externalapi.DomainHash
virtualFinalityPoint, err := csm.finalityManager.VirtualFinalityPoint()
if err != nil {
return false, false, err
}
log.Tracef("The virtual finality point is: %s", virtualFinalityPoint)
// There can be a situation where the virtual points close to the pruning point (or even in the past
// of the pruning point before calling validateAndInsertBlock for the pruning point block) and the
// finality point from the virtual point-of-view is in the past of the pruning point.
// In such situation we override the finality point to be the pruning point to avoid situations where
// the virtual selected parent chain don't include the pruning point.
pruningPoint, err := csm.pruningStore.PruningPoint(csm.databaseContext)
if err != nil {
return false, false, err
}
log.Tracef("The pruning point is: %s", pruningPoint)
isFinalityPointInPastOfPruningPoint, err := csm.dagTopologyManager.IsAncestorOf(virtualFinalityPoint, pruningPoint)
if err != nil {
return false, false, err
}
if !isFinalityPointInPastOfPruningPoint {
finalityPoint = virtualFinalityPoint
} else {
log.Tracef("The virtual finality point is %s in the past of the pruning point, so finality is validated "+
"using the pruning point", virtualFinalityPoint)
finalityPoint = pruningPoint
}
isInSelectedParentChainOfFinalityPoint, err := csm.dagTopologyManager.IsInSelectedParentChainOf(finalityPoint,
blockHash)
if err != nil {
return false, false, err
}
if !isInSelectedParentChainOfFinalityPoint {
if !isFinalityPointInPastOfPruningPoint {
return true, true, nil
}
// On IBD it's pretty normal to get blocks in the anticone of the pruning
// point, so we don't notify on cases when the pruning point is in the future
// of the finality point.
return true, false, nil
}
log.Tracef("Block %s does not violate finality", blockHash)
return nil
return false, false, nil
}

View File

@@ -25,16 +25,17 @@ type consensusStateManager struct {
mergeDepthManager model.MergeDepthManager
finalityManager model.FinalityManager
headerTipsStore model.HeaderTipsStore
blockStatusStore model.BlockStatusStore
ghostdagDataStore model.GHOSTDAGDataStore
consensusStateStore model.ConsensusStateStore
multisetStore model.MultisetStore
blockStore model.BlockStore
utxoDiffStore model.UTXODiffStore
blockRelationStore model.BlockRelationStore
acceptanceDataStore model.AcceptanceDataStore
blockHeaderStore model.BlockHeaderStore
headersSelectedTipStore model.HeaderSelectedTipStore
blockStatusStore model.BlockStatusStore
ghostdagDataStore model.GHOSTDAGDataStore
consensusStateStore model.ConsensusStateStore
multisetStore model.MultisetStore
blockStore model.BlockStore
utxoDiffStore model.UTXODiffStore
blockRelationStore model.BlockRelationStore
acceptanceDataStore model.AcceptanceDataStore
blockHeaderStore model.BlockHeaderStore
pruningStore model.PruningStore
stores []model.Store
}
@@ -68,7 +69,8 @@ func New(
blockRelationStore model.BlockRelationStore,
acceptanceDataStore model.AcceptanceDataStore,
blockHeaderStore model.BlockHeaderStore,
headerTipsStore model.HeaderTipsStore) (model.ConsensusStateManager, error) {
headersSelectedTipStore model.HeaderSelectedTipStore,
pruningStore model.PruningStore) (model.ConsensusStateManager, error) {
csm := &consensusStateManager{
pruningDepth: pruningDepth,
@@ -89,16 +91,17 @@ func New(
mergeDepthManager: mergeDepthManager,
finalityManager: finalityManager,
multisetStore: multisetStore,
blockStore: blockStore,
blockStatusStore: blockStatusStore,
ghostdagDataStore: ghostdagDataStore,
consensusStateStore: consensusStateStore,
utxoDiffStore: utxoDiffStore,
blockRelationStore: blockRelationStore,
acceptanceDataStore: acceptanceDataStore,
blockHeaderStore: blockHeaderStore,
headerTipsStore: headerTipsStore,
multisetStore: multisetStore,
blockStore: blockStore,
blockStatusStore: blockStatusStore,
ghostdagDataStore: ghostdagDataStore,
consensusStateStore: consensusStateStore,
utxoDiffStore: utxoDiffStore,
blockRelationStore: blockRelationStore,
acceptanceDataStore: acceptanceDataStore,
blockHeaderStore: blockHeaderStore,
headersSelectedTipStore: headersSelectedTipStore,
pruningStore: pruningStore,
stores: []model.Store{
consensusStateStore,
@@ -111,7 +114,8 @@ func New(
consensusStateStore,
utxoDiffStore,
blockHeaderStore,
headerTipsStore,
headersSelectedTipStore,
pruningStore,
},
}

View File

@@ -0,0 +1,54 @@
package consensusstatemanager
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
func (csm *consensusStateManager) calculateSelectedParentChainChanges(
oldVirtualSelectedParent, newVirtualSelectedParent *externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) {
// Walk down from the old virtual until we reach the common selected
// parent chain ancestor of oldVirtualSelectedParent and
// newVirtualSelectedParent. Note that this slice will be empty if
// oldVirtualSelectedParent is the selected parent of
// newVirtualSelectedParent
var removed []*externalapi.DomainHash
current := oldVirtualSelectedParent
for {
isCurrentInTheSelectedParentChainOfNewVirtualSelectedParent, err := csm.dagTopologyManager.IsInSelectedParentChainOf(current, newVirtualSelectedParent)
if err != nil {
return nil, err
}
if isCurrentInTheSelectedParentChainOfNewVirtualSelectedParent {
break
}
removed = append(removed, current)
currentGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, current)
if err != nil {
return nil, err
}
current = currentGHOSTDAGData.SelectedParent()
}
commonAncestor := current
// Walk down from the new virtual down to the common ancestor
var added []*externalapi.DomainHash
current = newVirtualSelectedParent
for *current != *commonAncestor {
added = append(added, current)
currentGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, current)
if err != nil {
return nil, err
}
current = currentGHOSTDAGData.SelectedParent()
}
// Reverse the order of `added` so that it's sorted from low hash to high hash
for i, j := 0, len(added)-1; i < j; i, j = i+1, j-1 {
added[i], added[j] = added[j], added[i]
}
return &externalapi.SelectedParentChainChanges{
Added: added,
Removed: removed,
}, nil
}

View File

@@ -0,0 +1,109 @@
package consensusstatemanager_test
import (
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
"github.com/kaspanet/kaspad/domain/dagconfig"
"testing"
)
func TestCalculateSelectedParentChainChanges(t *testing.T) {
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
factory := consensus.NewFactory()
consensus, teardown, err := factory.NewTestConsensus(params, "TestCalculateSelectedParentChainChanges")
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown(false)
// Add block A over the genesis
blockAHash, blockAInsertionResult, err := consensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("Error adding block A: %+v", err)
}
blockASelectedParentChainChanges := blockAInsertionResult.SelectedParentChainChanges
// Make sure that the removed slice is empty
if len(blockASelectedParentChainChanges.Removed) > 0 {
t.Fatalf("The `removed` slice is not empty after inserting block A")
}
// Make sure that the added slice contains only blockAHash
if len(blockASelectedParentChainChanges.Added) != 1 {
t.Fatalf("The `added` slice contains an unexpected amount of items after inserting block A. "+
"Want: %d, got: %d", 1, len(blockASelectedParentChainChanges.Added))
}
if *blockASelectedParentChainChanges.Added[0] != *blockAHash {
t.Fatalf("The `added` slice contains an unexpected hash. Want: %s, got: %s",
blockAHash, blockASelectedParentChainChanges.Added[0])
}
// Add block B over the genesis
blockBHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("Error adding block B: %+v", err)
}
// Figure out which among blocks A and B is NOT the virtual selected parent
virtualGHOSTDAGData, err := consensus.GHOSTDAGDataStore().Get(consensus.DatabaseContext(), model.VirtualBlockHash)
if err != nil {
t.Fatalf("Error getting virtual GHOSTDAG data: %+v", err)
}
virtualSelectedParent := virtualGHOSTDAGData.SelectedParent()
notVirtualSelectedParent := blockAHash
if *virtualSelectedParent == *blockAHash {
notVirtualSelectedParent = blockBHash
}
// Add block C over the block that isn't the current virtual's selected parent
// We expect this to cause a reorg
blockCHash, blockCInsertionResult, err := consensus.AddBlock([]*externalapi.DomainHash{notVirtualSelectedParent}, nil, nil)
if err != nil {
t.Fatalf("Error adding block C: %+v", err)
}
blockCSelectedParentChainChanges := blockCInsertionResult.SelectedParentChainChanges
// Make sure that the removed slice contains only the block that was previously
// the selected parent
if len(blockCSelectedParentChainChanges.Removed) != 1 {
t.Fatalf("The `removed` slice contains an unexpected amount of items after inserting block C. "+
"Want: %d, got: %d", 1, len(blockCSelectedParentChainChanges.Removed))
}
if *blockCSelectedParentChainChanges.Removed[0] != *virtualSelectedParent {
t.Fatalf("The `removed` slice contains an unexpected hash. "+
"Want: %s, got: %s", virtualSelectedParent, blockCSelectedParentChainChanges.Removed[0])
}
// Make sure that the added slice contains the block that was NOT previously
// the selected parent and blockCHash, in that order
if len(blockCSelectedParentChainChanges.Added) != 2 {
t.Fatalf("The `added` slice contains an unexpected amount of items after inserting block C. "+
"Want: %d, got: %d", 2, len(blockCSelectedParentChainChanges.Added))
}
if *blockCSelectedParentChainChanges.Added[0] != *notVirtualSelectedParent {
t.Fatalf("The `added` slice contains an unexpected hash as the first item. "+
"Want: %s, got: %s", notVirtualSelectedParent, blockCSelectedParentChainChanges.Added[0])
}
if *blockCSelectedParentChainChanges.Added[1] != *blockCHash {
t.Fatalf("The `added` slice contains an unexpected hash as the second item. "+
"Want: %s, got: %s", blockCHash, blockCSelectedParentChainChanges.Added[1])
}
// Add block D over the genesis
_, blockDInsertionResult, err := consensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("Error adding block D: %+v", err)
}
blockDSelectedParentChainChanges := blockDInsertionResult.SelectedParentChainChanges
// Make sure that both the added and the removed slices are empty
if len(blockDSelectedParentChainChanges.Added) > 0 {
t.Fatalf("The `added` slice is not empty after inserting block D")
}
if len(blockDSelectedParentChainChanges.Removed) > 0 {
t.Fatalf("The `removed` slice is not empty after inserting block D")
}
})
}

View File

@@ -25,14 +25,14 @@ func TestDoubleSpends(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
// Mine chain of two blocks to fund our double spend
firstBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
firstBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("Error creating firstBlock: %+v", err)
}
fundingBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{firstBlockHash}, nil, nil)
fundingBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{firstBlockHash}, nil, nil)
if err != nil {
t.Fatalf("Error creating fundingBlock: %+v", err)
}
@@ -61,7 +61,7 @@ func TestDoubleSpends(t *testing.T) {
}
// Mine a block with spendingTransaction1 and make sure that it's valid
goodBlock1Hash, err := consensus.AddBlock([]*externalapi.DomainHash{fundingBlockHash}, nil,
goodBlock1Hash, _, err := consensus.AddBlock([]*externalapi.DomainHash{fundingBlockHash}, nil,
[]*externalapi.DomainTransaction{spendingTransaction1})
if err != nil {
t.Fatalf("Error adding goodBlock1: %+v", err)
@@ -76,7 +76,7 @@ func TestDoubleSpends(t *testing.T) {
// To check that a block containing the same transaction already in it's past is disqualified:
// Add a block on top of goodBlock, containing spendingTransaction1, and make sure it's disqualified
doubleSpendingBlock1Hash, err := consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
doubleSpendingBlock1Hash, _, err := consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
[]*externalapi.DomainTransaction{spendingTransaction1})
if err != nil {
t.Fatalf("Error adding doubleSpendingBlock1: %+v", err)
@@ -93,7 +93,7 @@ func TestDoubleSpends(t *testing.T) {
// To check that a block containing a transaction that double-spends a transaction that
// is in it's past is disqualified:
// Add a block on top of goodBlock, containing spendingTransaction2, and make sure it's disqualified
doubleSpendingBlock2Hash, err := consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
doubleSpendingBlock2Hash, _, err := consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
[]*externalapi.DomainTransaction{spendingTransaction2})
if err != nil {
t.Fatalf("Error adding doubleSpendingBlock2: %+v", err)
@@ -110,7 +110,7 @@ func TestDoubleSpends(t *testing.T) {
// To make sure that a block double-spending itself is rejected:
// Add a block on top of goodBlock, containing both spendingTransaction1 and spendingTransaction2, and make
// sure AddBlock returns a RuleError
_, err = consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
_, _, err = consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
[]*externalapi.DomainTransaction{spendingTransaction1, spendingTransaction2})
if err == nil {
t.Fatalf("No error when adding a self-double-spending block")
@@ -123,7 +123,7 @@ func TestDoubleSpends(t *testing.T) {
// To make sure that a block containing the same transaction twice is rejected:
// Add a block on top of goodBlock, containing spendingTransaction1 twice, and make
// sure AddBlock returns a RuleError
_, err = consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
_, _, err = consensus.AddBlock([]*externalapi.DomainHash{goodBlock1Hash}, nil,
[]*externalapi.DomainTransaction{spendingTransaction1, spendingTransaction1})
if err == nil {
t.Fatalf("No error when adding a block containing the same transactin twice")
@@ -135,7 +135,7 @@ func TestDoubleSpends(t *testing.T) {
// Check that a block will not get disqualified if it has a transaction that double spends
// a transaction from its anticone.
goodBlock2Hash, err := consensus.AddBlock([]*externalapi.DomainHash{fundingBlockHash}, nil,
goodBlock2Hash, _, err := consensus.AddBlock([]*externalapi.DomainHash{fundingBlockHash}, nil,
[]*externalapi.DomainTransaction{spendingTransaction2})
if err != nil {
t.Fatalf("Error adding goodBlock: %+v", err)
@@ -157,7 +157,7 @@ func TestResolveBlockStatusSanity(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
genesisHash := params.GenesisHash
allHashes := []*externalapi.DomainHash{genesisHash}
@@ -177,7 +177,7 @@ func TestResolveBlockStatusSanity(t *testing.T) {
// statuses are valid
currentHash := genesisHash
for i := 0; i < chainLength; i++ {
addedBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
addedBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
if err != nil {
t.Fatalf("error adding block %d: %s", i, err)
}
@@ -197,7 +197,7 @@ func TestResolveBlockStatusSanity(t *testing.T) {
// StatusUTXOPendingVerification
currentHash = genesisHash
for i := 0; i < chainLength-1; i++ {
addedBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
addedBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
if err != nil {
t.Fatalf("error adding block %d: %s", i, err)
}
@@ -216,7 +216,7 @@ func TestResolveBlockStatusSanity(t *testing.T) {
// Add another two blocks to the second chain. This should trigger
// resolving the entire chain
for i := 0; i < 2; i++ {
addedBlockHash, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
addedBlockHash, _, err := consensus.AddBlock([]*externalapi.DomainHash{currentHash}, nil, nil)
if err != nil {
t.Fatalf("error adding block %d: %s", i, err)
}

View File

@@ -15,12 +15,12 @@ func NewTestConsensusStateManager(baseConsensusStateManager model.ConsensusState
return &testConsensusStateManager{consensusStateManager: baseConsensusStateManager.(*consensusStateManager)}
}
func (csm testConsensusStateManager) AddUTXOToMultiset(
func (csm *testConsensusStateManager) AddUTXOToMultiset(
multiset model.Multiset, entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) error {
return addUTXOToMultiset(multiset, entry, outpoint)
}
func (csm testConsensusStateManager) ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) {
func (csm *testConsensusStateManager) ResolveBlockStatus(blockHash *externalapi.DomainHash) (externalapi.BlockStatus, error) {
return csm.resolveBlockStatus(blockHash)
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
"github.com/kaspanet/kaspad/domain/consensus/utils/serialization"
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
"github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization"
@@ -12,18 +13,11 @@ import (
"github.com/pkg/errors"
)
var virtualHeaderHash = &externalapi.DomainHash{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
}
func (csm *consensusStateManager) SetPruningPointUTXOSet(serializedUTXOSet []byte) error {
onEnd := logger.LogAndMeasureExecutionTime(log, "SetPruningPointUTXOSet")
func (csm *consensusStateManager) UpdatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
onEnd := logger.LogAndMeasureExecutionTime(log, "UpdatePruningPoint")
defer onEnd()
err := csm.setPruningPointUTXOSet(serializedUTXOSet)
err := csm.updatePruningPoint(newPruningPoint, serializedUTXOSet)
if err != nil {
csm.discardSetPruningPointUTXOSetChanges()
return err
@@ -32,15 +26,23 @@ func (csm *consensusStateManager) SetPruningPointUTXOSet(serializedUTXOSet []byt
return csm.commitSetPruningPointUTXOSetAll()
}
func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byte) error {
log.Tracef("setPruningPointUTXOSet start")
defer log.Tracef("setPruningPointUTXOSet end")
func (csm *consensusStateManager) updatePruningPoint(newPruningPoint *externalapi.DomainBlock, serializedUTXOSet []byte) error {
log.Tracef("updatePruningPoint start")
defer log.Tracef("updatePruningPoint end")
headerTipsPruningPoint, err := csm.HeaderTipsPruningPoint()
newPruningPointHash := consensushashing.BlockHash(newPruningPoint)
// We ignore the shouldSendNotification return value because we always want to send finality conflict notification
// in case the new pruning point violates finality
isViolatingFinality, _, err := csm.isViolatingFinality(newPruningPointHash)
if err != nil {
return err
}
log.Tracef("The pruning point of the header tips is: %s", headerTipsPruningPoint)
if isViolatingFinality {
log.Warnf("Finality Violation Detected! The suggest pruning point %s violates finality!", newPruningPointHash)
return nil
}
protoUTXOSet := &utxoserialization.ProtoUTXOSet{}
err = proto.Unmarshal(serializedUTXOSet, protoUTXOSet)
@@ -54,24 +56,24 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
}
log.Tracef("Calculated multiset for given UTXO set: %s", utxoSetMultiSet.Hash())
headerTipsPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, headerTipsPruningPoint)
newPruningPointHeader, err := csm.blockHeaderStore.BlockHeader(csm.databaseContext, newPruningPointHash)
if err != nil {
return err
}
log.Tracef("The multiset in the header of the header tip pruning point: %s",
headerTipsPruningPointHeader.UTXOCommitment)
log.Tracef("The UTXO commitment of the pruning point: %s",
newPruningPointHeader.UTXOCommitment)
if headerTipsPruningPointHeader.UTXOCommitment != *utxoSetMultiSet.Hash() {
if newPruningPointHeader.UTXOCommitment != *utxoSetMultiSet.Hash() {
return errors.Wrapf(ruleerrors.ErrBadPruningPointUTXOSet, "the expected multiset hash of the pruning "+
"point UTXO set is %s but got %s", headerTipsPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash())
"point UTXO set is %s but got %s", newPruningPointHeader.UTXOCommitment, *utxoSetMultiSet.Hash())
}
log.Tracef("Header tip pruning point multiset validation passed")
log.Tracef("The new pruning point UTXO commitment validation passed")
log.Tracef("Staging the parent hashes for the header tips pruning point as the DAG tips")
csm.consensusStateStore.StageTips(headerTipsPruningPointHeader.ParentHashes)
log.Tracef("Staging the parent hashes for pruning point as the DAG tips")
csm.consensusStateStore.StageTips(newPruningPointHeader.ParentHashes)
log.Tracef("Setting the parent hashes for the header tips pruning point as the virtual parents")
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, headerTipsPruningPointHeader.ParentHashes)
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, newPruningPointHeader.ParentHashes)
if err != nil {
return err
}
@@ -82,6 +84,13 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
return err
}
// Before we manually mark the new pruning point as valid, we validate that all of its transactions are valid
// against the provided UTXO set.
err = csm.validateBlockTransactionsAgainstPastUTXO(newPruningPoint, utxo.NewUTXODiff())
if err != nil {
return err
}
err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash)
if err != nil {
return err
@@ -93,8 +102,11 @@ func (csm *consensusStateManager) setPruningPointUTXOSet(serializedUTXOSet []byt
return err
}
log.Tracef("Staging the status of the header tips pruning point as %s", externalapi.StatusValid)
csm.blockStatusStore.Stage(headerTipsPruningPoint, externalapi.StatusValid)
log.Tracef("Staging the new pruning point and its UTXO set")
csm.pruningStore.Stage(newPruningPointHash, serializedUTXOSet)
log.Tracef("Staging the new pruning point as %s", externalapi.StatusValid)
csm.blockStatusStore.Stage(newPruningPointHash, externalapi.StatusValid)
return nil
}
@@ -125,12 +137,12 @@ type protoUTXOSetIterator struct {
index int
}
func (p protoUTXOSetIterator) Next() bool {
func (p *protoUTXOSetIterator) Next() bool {
p.index++
return p.index < len(p.utxoSet.Utxos)
}
func (p protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) {
func (p *protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) {
entry, outpoint, err := utxo.DeserializeUTXO(p.utxoSet.Utxos[p.index].EntryOutpointPair)
if err != nil {
if serialization.IsMalformedError(err) {
@@ -145,34 +157,3 @@ func (p protoUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoE
func protoUTXOSetToReadOnlyUTXOSetIterator(protoUTXOSet *utxoserialization.ProtoUTXOSet) model.ReadOnlyUTXOSetIterator {
return &protoUTXOSetIterator{utxoSet: protoUTXOSet}
}
func (csm *consensusStateManager) HeaderTipsPruningPoint() (*externalapi.DomainHash, error) {
log.Tracef("HeaderTipsPruningPoint start")
defer log.Tracef("HeaderTipsPruningPoint end")
headerTips, err := csm.headerTipsStore.Tips(csm.databaseContext)
if err != nil {
return nil, err
}
log.Tracef("The current header tips are: %s", headerTips)
log.Tracef("Temporarily staging the parents of the virtual header to be the header tips: %s", headerTips)
csm.blockRelationStore.StageBlockRelation(virtualHeaderHash, &model.BlockRelations{
Parents: headerTips,
})
defer csm.blockRelationStore.Discard()
err = csm.ghostdagManager.GHOSTDAG(virtualHeaderHash)
if err != nil {
return nil, err
}
defer csm.ghostdagDataStore.Discard()
pruningPoint, err := csm.dagTraversalManager.BlockAtDepth(virtualHeaderHash, csm.pruningDepth)
if err != nil {
return nil, err
}
log.Tracef("The block at depth %d from %s is: %s", csm.pruningDepth, virtualHeaderHash, pruningPoint)
return pruningPoint, nil
}

View File

@@ -5,32 +5,44 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.DomainHash, tips []*externalapi.DomainHash) error {
func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.DomainHash,
tips []*externalapi.DomainHash) (*externalapi.SelectedParentChainChanges, error) {
log.Tracef("updateVirtual start for block %s", newBlockHash)
defer log.Tracef("updateVirtual end for block %s", newBlockHash)
log.Tracef("Saving a reference to the GHOSTDAG data of the old virtual")
var oldVirtualSelectedParent *externalapi.DomainHash
if *newBlockHash != *csm.genesisHash {
oldVirtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash)
if err != nil {
return nil, err
}
oldVirtualSelectedParent = oldVirtualGHOSTDAGData.SelectedParent()
}
log.Tracef("Picking virtual parents from the tips: %s", tips)
virtualParents, err := csm.pickVirtualParents(tips)
if err != nil {
return err
return nil, err
}
log.Tracef("Picked virtual parents: %s", virtualParents)
err = csm.dagTopologyManager.SetParents(model.VirtualBlockHash, virtualParents)
if err != nil {
return err
return nil, err
}
log.Tracef("Set new parents for the virtual block hash")
err = csm.ghostdagManager.GHOSTDAG(model.VirtualBlockHash)
if err != nil {
return err
return nil, err
}
log.Tracef("Calculating past UTXO, acceptance data, and multiset for the new virtual block")
virtualUTXODiff, virtualAcceptanceData, virtualMultiset, err := csm.CalculatePastUTXOAndAcceptanceData(model.VirtualBlockHash)
if err != nil {
return err
return nil, err
}
log.Tracef("Staging new acceptance data for the virtual block")
@@ -42,16 +54,30 @@ func (csm *consensusStateManager) updateVirtual(newBlockHash *externalapi.Domain
log.Tracef("Staging new UTXO diff for the virtual block")
err = csm.consensusStateStore.StageVirtualUTXODiff(virtualUTXODiff)
if err != nil {
return err
return nil, err
}
log.Tracef("Updating the virtual diff parents after adding %s to the DAG", newBlockHash)
err = csm.updateVirtualDiffParents(virtualUTXODiff)
if err != nil {
return err
return nil, err
}
return nil
log.Tracef("Calculating selected parent chain changes")
var selectedParentChainChanges *externalapi.SelectedParentChainChanges
if *newBlockHash != *csm.genesisHash {
newVirtualGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, model.VirtualBlockHash)
if err != nil {
return nil, err
}
newVirtualSelectedParent := newVirtualGHOSTDAGData.SelectedParent()
selectedParentChainChanges, err = csm.calculateSelectedParentChainChanges(oldVirtualSelectedParent, newVirtualSelectedParent)
if err != nil {
return nil, err
}
}
return selectedParentChainChanges, nil
}
func (csm *consensusStateManager) updateVirtualDiffParents(virtualUTXODiff model.UTXODiff) error {

View File

@@ -47,7 +47,7 @@ func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blo
log.Tracef("Coinbase transaction validation passed for block %s", blockHash)
log.Tracef("Validating transactions against past UTXO for block %s", blockHash)
err = csm.validateBlockTransactionsAgainstPastUTXO(block, blockHash, pastUTXODiff)
err = csm.validateBlockTransactionsAgainstPastUTXO(block, pastUTXODiff)
if err != nil {
return err
}
@@ -57,8 +57,9 @@ func (csm *consensusStateManager) verifyUTXO(block *externalapi.DomainBlock, blo
}
func (csm *consensusStateManager) validateBlockTransactionsAgainstPastUTXO(block *externalapi.DomainBlock,
blockHash *externalapi.DomainHash, pastUTXODiff model.UTXODiff) error {
pastUTXODiff model.UTXODiff) error {
blockHash := consensushashing.BlockHash(block)
log.Tracef("validateBlockTransactionsAgainstPastUTXO start for block %s", blockHash)
defer log.Tracef("validateBlockTransactionsAgainstPastUTXO end for block %s", blockHash)

View File

@@ -16,28 +16,28 @@ func TestIsAncestorOf(t *testing.T) {
if err != nil {
t.Fatalf("NewTestConsensus: %s", err)
}
defer tearDown()
defer tearDown(false)
// Add a chain of two blocks above the genesis. This will be the
// selected parent chain.
blockA, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
blockA, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
blockB, err := tc.AddBlock([]*externalapi.DomainHash{blockA}, nil, nil)
blockB, _, err := tc.AddBlock([]*externalapi.DomainHash{blockA}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %s", err)
}
// Add another block above the genesis
blockC, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
blockC, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %s", err)
}
// Add a block whose parents are the two tips
blockD, err := tc.AddBlock([]*externalapi.DomainHash{blockB, blockC}, nil, nil)
blockD, _, err := tc.AddBlock([]*externalapi.DomainHash{blockB, blockC}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %s", err)
}

View File

@@ -22,8 +22,8 @@ type baseHeap struct {
ghostdagManager model.GHOSTDAGManager
}
func (h baseHeap) Len() int { return len(h.slice) }
func (h baseHeap) Swap(i, j int) { h.slice[i], h.slice[j] = h.slice[j], h.slice[i] }
func (h *baseHeap) Len() int { return len(h.slice) }
func (h *baseHeap) Swap(i, j int) { h.slice[i], h.slice[j] = h.slice[j], h.slice[i] }
func (h *baseHeap) Push(x interface{}) {
h.slice = append(h.slice, x.(*blockHeapNode))
@@ -45,7 +45,7 @@ func (h *baseHeap) peek() *blockHeapNode {
// upHeap extends baseHeap to include Less operation that traverses from bottom to top
type upHeap struct{ baseHeap }
func (h upHeap) Less(i, j int) bool {
func (h *upHeap) Less(i, j int) bool {
heapNodeI := h.slice[i]
heapNodeJ := h.slice[j]
return heapNodeI.less(heapNodeJ, h.ghostdagManager)
@@ -54,7 +54,7 @@ func (h upHeap) Less(i, j int) bool {
// downHeap extends baseHeap to include Less operation that traverses from top to bottom
type downHeap struct{ baseHeap }
func (h downHeap) Less(i, j int) bool {
func (h *downHeap) Less(i, j int) bool {
heapNodeI := h.slice[i]
heapNodeJ := h.slice[j]
return !heapNodeI.less(heapNodeJ, h.ghostdagManager)
@@ -68,34 +68,34 @@ type blockHeap struct {
}
// NewDownHeap initializes and returns a new blockHeap
func (dtm dagTraversalManager) NewDownHeap() model.BlockHeap {
func (dtm *dagTraversalManager) NewDownHeap() model.BlockHeap {
h := blockHeap{
impl: &downHeap{baseHeap{ghostdagManager: dtm.ghostdagManager}},
ghostdagStore: dtm.ghostdagDataStore,
dbContext: dtm.databaseContext,
}
heap.Init(h.impl)
return h
return &h
}
// NewUpHeap initializes and returns a new blockHeap
func (dtm dagTraversalManager) NewUpHeap() model.BlockHeap {
func (dtm *dagTraversalManager) NewUpHeap() model.BlockHeap {
h := blockHeap{
impl: &upHeap{baseHeap{ghostdagManager: dtm.ghostdagManager}},
ghostdagStore: dtm.ghostdagDataStore,
dbContext: dtm.databaseContext,
}
heap.Init(h.impl)
return h
return &h
}
// Pop removes the block with lowest blueWork+hash from this heap and returns it
func (bh blockHeap) Pop() *externalapi.DomainHash {
func (bh *blockHeap) Pop() *externalapi.DomainHash {
return heap.Pop(bh.impl).(*blockHeapNode).hash
}
// Push pushes the block onto the heap
func (bh blockHeap) Push(blockHash *externalapi.DomainHash) error {
func (bh *blockHeap) Push(blockHash *externalapi.DomainHash) error {
ghostdagData, err := bh.ghostdagStore.Get(bh.dbContext, blockHash)
if err != nil {
return err
@@ -110,7 +110,7 @@ func (bh blockHeap) Push(blockHash *externalapi.DomainHash) error {
}
// Len returns the length of this heap
func (bh blockHeap) Len() int {
func (bh *blockHeap) Len() int {
return bh.impl.Len()
}
@@ -122,7 +122,7 @@ type sizedUpBlockHeap struct {
}
// newSizedUpHeap initializes and returns a new sizedUpBlockHeap
func (dtm dagTraversalManager) newSizedUpHeap(cap int) *sizedUpBlockHeap {
func (dtm *dagTraversalManager) newSizedUpHeap(cap int) *sizedUpBlockHeap {
h := sizedUpBlockHeap{
impl: upHeap{baseHeap{slice: make([]*blockHeapNode, 0, cap), ghostdagManager: dtm.ghostdagManager}},
ghostdagStore: dtm.ghostdagDataStore,

View File

@@ -2,9 +2,9 @@ package dagtraversalmanager
import (
"fmt"
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/pkg/errors"
)
// dagTraversalManager exposes methods for travering blocks
@@ -100,6 +100,11 @@ func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash
return nil, err
}
if highBlockGHOSTDAGData.BlueScore() < blueScore {
return nil, errors.Errorf("the given blue score %d is higher than block %s blue score of %d",
blueScore, highHash, highBlockGHOSTDAGData.BlueScore())
}
currentHash := highHash
currentBlockGHOSTDAGData := highBlockGHOSTDAGData
iterator := dtm.SelectedParentIterator(highHash)
@@ -112,7 +117,7 @@ func (dtm *dagTraversalManager) LowestChainBlockAboveOrEqualToBlueScore(highHash
if selectedParentBlockGHOSTDAGData.BlueScore() < blueScore {
break
}
currentHash = selectedParentBlockGHOSTDAGData.SelectedParent()
currentHash = currentBlockGHOSTDAGData.SelectedParent()
currentBlockGHOSTDAGData = selectedParentBlockGHOSTDAGData
}

View File

@@ -37,7 +37,7 @@ func (s *selectedChildIterator) Next() bool {
return false
}
func (s selectedChildIterator) Get() *externalapi.DomainHash {
func (s *selectedChildIterator) Get() *externalapi.DomainHash {
return s.current
}

View File

@@ -1,14 +1,15 @@
package dagtraversalmanager_test
import (
"reflect"
"testing"
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/hashset"
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
"github.com/kaspanet/kaspad/domain/dagconfig"
"github.com/pkg/errors"
"reflect"
"testing"
)
func TestBlueBlockWindow(t *testing.T) {
@@ -313,7 +314,7 @@ func TestBlueBlockWindow(t *testing.T) {
if err != nil {
t.Fatalf("NewTestConsensus: %s", err)
}
defer tearDown()
defer tearDown(false)
windowSize := 10
blockByIDMap := make(map[string]*externalapi.DomainHash)
@@ -330,7 +331,7 @@ func TestBlueBlockWindow(t *testing.T) {
parents.Add(parent)
}
block, err := tc.AddBlock(parents.ToSlice(), nil, nil)
block, _, err := tc.AddBlock(parents.ToSlice(), nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}

View File

@@ -26,7 +26,7 @@ func TestDifficulty(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
addBlock := func(blockTime int64, parents ...*externalapi.DomainHash) (*externalapi.DomainBlock, *externalapi.DomainHash) {
bluestParent, err := tc.GHOSTDAGManager().ChooseSelectedParent(parents...)
@@ -49,7 +49,7 @@ func TestDifficulty(t *testing.T) {
}
block.Header.TimeInMilliseconds = blockTime
err = tc.ValidateAndInsertBlock(block)
_, err = tc.ValidateAndInsertBlock(block)
if err != nil {
t.Fatalf("ValidateAndInsertBlock: %+v", err)
}

View File

@@ -35,31 +35,6 @@ func New(databaseContext model.DBReader,
}
}
func (fm *finalityManager) IsViolatingFinality(blockHash *externalapi.DomainHash) (bool, error) {
if *blockHash == *fm.genesisHash {
log.Tracef("Block %s is the genesis block, "+
"and does not violate finality by definition", blockHash)
return false, nil
}
log.Tracef("isViolatingFinality start for block %s", blockHash)
defer log.Tracef("isViolatingFinality end for block %s", blockHash)
virtualFinalityPoint, err := fm.VirtualFinalityPoint()
if err != nil {
return false, err
}
log.Tracef("The virtual finality point is: %s", virtualFinalityPoint)
isInSelectedParentChain, err := fm.dagTopologyManager.IsInSelectedParentChainOf(virtualFinalityPoint, blockHash)
if err != nil {
return false, err
}
log.Tracef("Is the virtual finality point %s "+
"in the selected parent chain of %s: %t", virtualFinalityPoint, blockHash, isInSelectedParentChain)
return !isInSelectedParentChain, nil
}
func (fm *finalityManager) VirtualFinalityPoint() (*externalapi.DomainHash, error) {
log.Tracef("virtualFinalityPoint start")
defer log.Tracef("virtualFinalityPoint end")

View File

@@ -343,6 +343,6 @@ func (b *blockHeadersStore) Delete(blockHash *externalapi.DomainHash) {
delete(b.dagMap, *blockHash)
}
func (b blockHeadersStore) Count() uint64 {
func (b *blockHeadersStore) Count() uint64 {
return uint64(len(b.dagMap))
}

View File

@@ -0,0 +1,55 @@
package headersselectedtipmanager
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
type headerTipsManager struct {
databaseContext model.DBReader
dagTopologyManager model.DAGTopologyManager
ghostdagManager model.GHOSTDAGManager
headersSelectedTipStore model.HeaderSelectedTipStore
}
// New instantiates a new HeadersSelectedTipManager
func New(databaseContext model.DBReader,
dagTopologyManager model.DAGTopologyManager,
ghostdagManager model.GHOSTDAGManager,
headersSelectedTipStore model.HeaderSelectedTipStore) model.HeadersSelectedTipManager {
return &headerTipsManager{
databaseContext: databaseContext,
dagTopologyManager: dagTopologyManager,
ghostdagManager: ghostdagManager,
headersSelectedTipStore: headersSelectedTipStore,
}
}
func (h *headerTipsManager) AddHeaderTip(hash *externalapi.DomainHash) error {
hasSelectedTip, err := h.headersSelectedTipStore.Has(h.databaseContext)
if err != nil {
return err
}
if !hasSelectedTip {
h.headersSelectedTipStore.Stage(hash)
} else {
headersSelectedTip, err := h.headersSelectedTipStore.HeadersSelectedTip(h.databaseContext)
if err != nil {
return err
}
newHeadersSelectedTip, err := h.ghostdagManager.ChooseSelectedParent(headersSelectedTip, hash)
if err != nil {
return err
}
if *newHeadersSelectedTip != *headersSelectedTip {
h.headersSelectedTipStore.Stage(newHeadersSelectedTip)
}
}
return nil
}

View File

@@ -1,59 +0,0 @@
package headertipsmanager
import (
"github.com/kaspanet/kaspad/domain/consensus/model"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
type headerTipsManager struct {
databaseContext model.DBReader
dagTopologyManager model.DAGTopologyManager
ghostdagManager model.GHOSTDAGManager
headerTipsStore model.HeaderTipsStore
}
// New instantiates a new HeaderTipsManager
func New(databaseContext model.DBReader,
dagTopologyManager model.DAGTopologyManager,
ghostdagManager model.GHOSTDAGManager,
headerTipsStore model.HeaderTipsStore) model.HeaderTipsManager {
return &headerTipsManager{
databaseContext: databaseContext,
dagTopologyManager: dagTopologyManager,
ghostdagManager: ghostdagManager,
headerTipsStore: headerTipsStore,
}
}
func (h headerTipsManager) AddHeaderTip(hash *externalapi.DomainHash) error {
tips := []*externalapi.DomainHash{}
hasTips, err := h.headerTipsStore.HasTips(h.databaseContext)
if err != nil {
return err
}
if hasTips {
var err error
tips, err = h.headerTipsStore.Tips(h.databaseContext)
if err != nil {
return err
}
}
newTips := make([]*externalapi.DomainHash, 0, len(tips)+1)
for _, tip := range tips {
isAncestorOf, err := h.dagTopologyManager.IsAncestorOf(tip, hash)
if err != nil {
return err
}
if !isAncestorOf {
newTips = append(newTips, tip)
}
}
newTips = append(newTips, hash)
h.headerTipsStore.Stage(newTips)
return nil
}

View File

@@ -1,17 +0,0 @@
package headertipsmanager
import "github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
func (h headerTipsManager) SelectedTip() (*externalapi.DomainHash, error) {
tips, err := h.headerTipsStore.Tips(h.databaseContext)
if err != nil {
return nil, err
}
selectedTip, err := h.ghostdagManager.ChooseSelectedParent(tips...)
if err != nil {
return nil, err
}
return selectedTip, nil
}

View File

@@ -79,7 +79,7 @@ func (mdm *mergeDepthManager) CheckBoundedMergeDepth(blockHash *externalapi.Doma
return nil
}
func (mdm mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
func (mdm *mergeDepthManager) NonBoundedMergeDepthViolatingBlues(blockHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
ghostdagData, err := mdm.ghostdagDataStore.Get(mdm.databaseContext, blockHash)
if err != nil {
return nil, err

View File

@@ -17,7 +17,7 @@ func TestPastMedianTime(t *testing.T) {
if err != nil {
t.Fatalf("NewTestConsensus: %s", err)
}
defer tearDown()
defer tearDown(false)
numBlocks := uint32(300)
blockHashes := make([]*externalapi.DomainHash, numBlocks)
@@ -31,7 +31,7 @@ func TestPastMedianTime(t *testing.T) {
}
block.Header.TimeInMilliseconds = blockTime
err = tc.ValidateAndInsertBlock(block)
_, err = tc.ValidateAndInsertBlock(block)
if err != nil {
t.Fatalf("ValidateAndInsertBlock: %+v", err)
}

View File

@@ -0,0 +1,5 @@
package pruningmanager
import "github.com/kaspanet/kaspad/infrastructure/logger"
var log, _ = logger.Get(logger.SubsystemTags.PRNM)

View File

@@ -11,13 +11,14 @@ import (
type pruningManager struct {
databaseContext model.DBReader
dagTraversalManager model.DAGTraversalManager
dagTopologyManager model.DAGTopologyManager
consensusStateManager model.ConsensusStateManager
consensusStateStore model.ConsensusStateStore
ghostdagDataStore model.GHOSTDAGDataStore
pruningStore model.PruningStore
blockStatusStore model.BlockStatusStore
dagTraversalManager model.DAGTraversalManager
dagTopologyManager model.DAGTopologyManager
consensusStateManager model.ConsensusStateManager
consensusStateStore model.ConsensusStateStore
ghostdagDataStore model.GHOSTDAGDataStore
pruningStore model.PruningStore
blockStatusStore model.BlockStatusStore
headerSelectedTipStore model.HeaderSelectedTipStore
multiSetStore model.MultisetStore
acceptanceDataStore model.AcceptanceDataStore
@@ -40,6 +41,7 @@ func New(
ghostdagDataStore model.GHOSTDAGDataStore,
pruningStore model.PruningStore,
blockStatusStore model.BlockStatusStore,
headerSelectedTipStore model.HeaderSelectedTipStore,
multiSetStore model.MultisetStore,
acceptanceDataStore model.AcceptanceDataStore,
@@ -52,27 +54,28 @@ func New(
) model.PruningManager {
return &pruningManager{
databaseContext: databaseContext,
dagTraversalManager: dagTraversalManager,
dagTopologyManager: dagTopologyManager,
consensusStateManager: consensusStateManager,
consensusStateStore: consensusStateStore,
ghostdagDataStore: ghostdagDataStore,
pruningStore: pruningStore,
blockStatusStore: blockStatusStore,
multiSetStore: multiSetStore,
acceptanceDataStore: acceptanceDataStore,
blocksStore: blocksStore,
utxoDiffStore: utxoDiffStore,
genesisHash: genesisHash,
pruningDepth: pruningDepth,
finalityInterval: finalityInterval,
databaseContext: databaseContext,
dagTraversalManager: dagTraversalManager,
dagTopologyManager: dagTopologyManager,
consensusStateManager: consensusStateManager,
consensusStateStore: consensusStateStore,
ghostdagDataStore: ghostdagDataStore,
pruningStore: pruningStore,
blockStatusStore: blockStatusStore,
multiSetStore: multiSetStore,
acceptanceDataStore: acceptanceDataStore,
blocksStore: blocksStore,
utxoDiffStore: utxoDiffStore,
headerSelectedTipStore: headerSelectedTipStore,
genesisHash: genesisHash,
pruningDepth: pruningDepth,
finalityInterval: finalityInterval,
}
}
// FindNextPruningPoint finds the next pruning point from the
// given blockHash
func (pm *pruningManager) FindNextPruningPoint() error {
func (pm *pruningManager) UpdatePruningPointByVirtual() error {
hasPruningPoint, err := pm.pruningStore.HasPruningPoint(pm.databaseContext)
if err != nil {
return err
@@ -95,40 +98,41 @@ func (pm *pruningManager) FindNextPruningPoint() error {
return err
}
virtualSelectedParent, err := pm.ghostdagDataStore.Get(pm.databaseContext, virtual.SelectedParent())
if err != nil {
return err
}
currentPGhost, err := pm.ghostdagDataStore.Get(pm.databaseContext, currentP)
if err != nil {
return err
}
currentPBlueScore := currentPGhost.BlueScore()
// Because the pruning point changes only once per finality, then there's no need to even check for that if a finality interval hasn't passed.
if virtual.BlueScore() <= currentPBlueScore+pm.finalityInterval {
if virtualSelectedParent.BlueScore() <= currentPBlueScore+pm.finalityInterval {
return nil
}
// This means the pruning point is still genesis.
if virtual.BlueScore() <= pm.pruningDepth+pm.finalityInterval {
if virtualSelectedParent.BlueScore() <= pm.pruningDepth+pm.finalityInterval {
return nil
}
// get Virtual(pruningDepth)
candidatePHash, err := pm.dagTraversalManager.BlockAtDepth(model.VirtualBlockHash, pm.pruningDepth)
if err != nil {
return err
}
candidatePGhost, err := pm.ghostdagDataStore.Get(pm.databaseContext, candidatePHash)
newPruningPoint, err := pm.calculatePruningPointFromBlock(model.VirtualBlockHash)
if err != nil {
return err
}
// Actually check if the pruning point changed
if (currentPBlueScore / pm.finalityInterval) < (candidatePGhost.BlueScore() / pm.finalityInterval) {
err = pm.savePruningPoint(candidatePHash)
if *newPruningPoint != *currentP {
err = pm.savePruningPoint(newPruningPoint)
if err != nil {
return err
}
return pm.deletePastBlocks(candidatePHash)
return pm.deletePastBlocks(newPruningPoint)
}
return pm.deletePastBlocks(currentP)
return nil
}
func (pm *pruningManager) deletePastBlocks(pruningPoint *externalapi.DomainHash) error {
@@ -233,6 +237,30 @@ func (pm *pruningManager) deleteBlock(blockHash *externalapi.DomainHash) (alread
return false, nil
}
func (pm *pruningManager) CalculatePruningPointByHeaderSelectedTip() (*externalapi.DomainHash, error) {
headersSelectedTip, err := pm.headerSelectedTipStore.HeadersSelectedTip(pm.databaseContext)
if err != nil {
return nil, err
}
return pm.calculatePruningPointFromBlock(headersSelectedTip)
}
func (pm *pruningManager) calculatePruningPointFromBlock(blockHash *externalapi.DomainHash) (*externalapi.DomainHash, error) {
ghostdagData, err := pm.ghostdagDataStore.Get(pm.databaseContext, blockHash)
if err != nil {
return nil, err
}
targetBlueScore := uint64(0)
if ghostdagData.BlueScore() > pm.pruningDepth {
// The target blue is calculated by calculating ghostdagData.BlueScore() - pm.pruningDepth and rounding
// down with the precision of finality interval.
targetBlueScore = ((ghostdagData.BlueScore() - pm.pruningDepth) / pm.finalityInterval) * pm.finalityInterval
}
return pm.dagTraversalManager.LowestChainBlockAboveOrEqualToBlueScore(blockHash, targetBlueScore)
}
func serializeUTXOSetIterator(iter model.ReadOnlyUTXOSetIterator) ([]byte, error) {
serializedUtxo, err := utxoserialization.ReadOnlyUTXOSetToProtoUTXOSet(iter)
if err != nil {

View File

@@ -1,11 +1,12 @@
package reachabilitymanager_test
import (
"testing"
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
"github.com/kaspanet/kaspad/domain/dagconfig"
"testing"
)
func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *testing.T) {
@@ -16,7 +17,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t
if err != nil {
t.Fatalf("NewTestConsensus: %+v", err)
}
defer tearDown()
defer tearDown(false)
tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow)
@@ -30,7 +31,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t
}
// Add a block on top of the genesis block
chainRootBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
chainRootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -39,7 +40,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t
// This should move the reindex root
chainRootBlockTipHash := chainRootBlock
for i := uint64(0); i < reachabilityReindexWindow; i++ {
chainBlock, err := tc.AddBlock([]*externalapi.DomainHash{chainRootBlockTipHash}, nil, nil)
chainBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{chainRootBlockTipHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -56,7 +57,7 @@ func TestAddChildThatPointsDirectlyToTheSelectedParentChainBelowReindexRoot(t *t
}
// Add another block over genesis
_, err = tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
_, _, err = tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -71,7 +72,7 @@ func TestUpdateReindexRoot(t *testing.T) {
if err != nil {
t.Fatalf("NewTestConsensus: %s", err)
}
defer tearDown()
defer tearDown(false)
tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow)
@@ -84,12 +85,12 @@ func TestUpdateReindexRoot(t *testing.T) {
}
// Add two blocks on top of the genesis block
chain1RootBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
chain1RootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
chain2RootBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
chain2RootBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -98,12 +99,12 @@ func TestUpdateReindexRoot(t *testing.T) {
chain1Tip, chain2Tip := chain1RootBlock, chain2RootBlock
for i := uint64(0); i < reachabilityReindexWindow-1; i++ {
var err error
chain1Tip, err = tc.AddBlock([]*externalapi.DomainHash{chain1Tip}, nil, nil)
chain1Tip, _, err = tc.AddBlock([]*externalapi.DomainHash{chain1Tip}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
chain2Tip, err = tc.AddBlock([]*externalapi.DomainHash{chain2Tip}, nil, nil)
chain2Tip, _, err = tc.AddBlock([]*externalapi.DomainHash{chain2Tip}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -119,7 +120,7 @@ func TestUpdateReindexRoot(t *testing.T) {
}
// Add another block over chain1. This will move the reindex root to chain1RootBlock
_, err = tc.AddBlock([]*externalapi.DomainHash{chain1Tip}, nil, nil)
_, _, err = tc.AddBlock([]*externalapi.DomainHash{chain1Tip}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -159,9 +160,9 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
factory := consensus.NewFactory()
tc, tearDown, err := factory.NewTestConsensus(params, "TestUpdateReindexRoot")
if err != nil {
t.Fatalf("NewTestConsensus: %s", err)
t.Fatalf("NewTestConsensus: %+v", err)
}
defer tearDown()
defer tearDown(false)
tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow)
@@ -174,17 +175,17 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
}
// Add three children to the genesis: leftBlock, centerBlock, rightBlock
leftBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
leftBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
centerBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
centerBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
rightBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
rightBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -194,7 +195,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
centerTipHash := centerBlock
for i := uint64(0); i < reachabilityReindexWindow; i++ {
var err error
centerTipHash, err = tc.AddBlock([]*externalapi.DomainHash{centerTipHash}, nil, nil)
centerTipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{centerTipHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -246,7 +247,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
leftTipHash := leftBlock
for i := uint64(0); i < reachabilityReindexWindow-1; i++ {
var err error
leftTipHash, err = tc.AddBlock([]*externalapi.DomainHash{leftTipHash}, nil, nil)
leftTipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{leftTipHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -269,7 +270,7 @@ func TestReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
rightTipHash := rightBlock
for i := uint64(0); i < reachabilityReindexWindow-1; i++ {
var err error
rightTipHash, err = tc.AddBlock([]*externalapi.DomainHash{rightTipHash}, nil, nil)
rightTipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{rightTipHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -295,7 +296,7 @@ func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
if err != nil {
t.Fatalf("NewTestConsensus: %s", err)
}
defer tearDown()
defer tearDown(false)
tc.ReachabilityManager().SetReachabilityReindexWindow(reachabilityReindexWindow)
@@ -303,7 +304,7 @@ func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
// This will set the reindex root to the child of genesis
chainTipHash := params.GenesisHash
for i := uint64(0); i < reachabilityReindexWindow+1; i++ {
chainTipHash, err = tc.AddBlock([]*externalapi.DomainHash{chainTipHash}, nil, nil)
chainTipHash, _, err = tc.AddBlock([]*externalapi.DomainHash{chainTipHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
@@ -311,14 +312,14 @@ func TestTipsAfterReindexIntervalsEarlierThanReindexRoot(t *testing.T) {
// Add another block above the genesis block. This will trigger an
// earlier-than-reindex-root reindex
sideBlock, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
sideBlock, _, err := tc.AddBlock([]*externalapi.DomainHash{params.GenesisHash}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}
// Add a block whose parents are the chain tip and the side block.
// We expect this not to fail
_, err = tc.AddBlock([]*externalapi.DomainHash{sideBlock}, nil, nil)
_, _, err = tc.AddBlock([]*externalapi.DomainHash{sideBlock}, nil, nil)
if err != nil {
t.Fatalf("AddBlock: %+v", err)
}

View File

@@ -9,15 +9,15 @@ type testReachabilityManager struct {
*reachabilityManager
}
func (t testReachabilityManager) ReachabilityReindexSlack() uint64 {
func (t *testReachabilityManager) ReachabilityReindexSlack() uint64 {
return t.reachabilityManager.reindexSlack
}
func (t testReachabilityManager) SetReachabilityReindexSlack(reindexSlack uint64) {
func (t *testReachabilityManager) SetReachabilityReindexSlack(reindexSlack uint64) {
t.reachabilityManager.reindexSlack = reindexSlack
}
func (t testReachabilityManager) SetReachabilityReindexWindow(reindexWindow uint64) {
func (t *testReachabilityManager) SetReachabilityReindexWindow(reindexWindow uint64) {
t.reachabilityManager.reindexWindow = reindexWindow
}

View File

@@ -16,19 +16,17 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
if err != nil {
return nil, err
}
lowBlockBlueScore := lowBlockGHOSTDAGData.BlueScore()
highBlockGHOSTDAGData, err := sm.ghostdagDataStore.Get(sm.databaseContext, highHash)
if err != nil {
return nil, err
}
highBlockBlueScore := highBlockGHOSTDAGData.BlueScore()
if lowBlockBlueScore >= highBlockBlueScore {
if lowBlockGHOSTDAGData.BlueScore() >= highBlockGHOSTDAGData.BlueScore() {
return nil, errors.Errorf("low hash blueScore >= high hash blueScore (%d >= %d)",
lowBlockBlueScore, highBlockBlueScore)
lowBlockGHOSTDAGData.BlueScore(), highBlockGHOSTDAGData.BlueScore())
}
// In order to get no more then maxHashesInAntiPastHashesBetween
// blocks from th future of the lowHash (including itself),
// blocks from the future of the lowHash (including itself),
// we iterate the selected parent chain of the highNode and
// stop once we reach
// highBlockBlueScore-lowBlockBlueScore+1 <= maxHashesInAntiPastHashesBetween.
@@ -36,8 +34,13 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
// Using blueScore as an approximation is considered to be
// fairly accurate because we presume that most DAG blocks are
// blue.
for highBlockBlueScore-lowBlockBlueScore+1 > maxHashesInAntiPastHashesBetween {
for highBlockGHOSTDAGData.BlueScore()-lowBlockGHOSTDAGData.BlueScore()+1 > maxHashesInAntiPastHashesBetween {
highHash = highBlockGHOSTDAGData.SelectedParent()
var err error
highBlockGHOSTDAGData, err = sm.ghostdagDataStore.Get(sm.databaseContext, highHash)
if err != nil {
return nil, err
}
}
// Collect every node in highHash's past (including itself) but
@@ -99,26 +102,26 @@ func (sm *syncManager) antiPastHashesBetween(lowHash, highHash *externalapi.Doma
}
func (sm *syncManager) missingBlockBodyHashes(highHash *externalapi.DomainHash) ([]*externalapi.DomainHash, error) {
headerTipsPruningPoint, err := sm.consensusStateManager.HeaderTipsPruningPoint()
pruningPoint, err := sm.pruningStore.PruningPoint(sm.databaseContext)
if err != nil {
return nil, err
}
selectedChildIterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, headerTipsPruningPoint)
selectedChildIterator, err := sm.dagTraversalManager.SelectedChildIterator(highHash, pruningPoint)
if err != nil {
return nil, err
}
lowHash := headerTipsPruningPoint
lowHash := pruningPoint
foundHeaderOnlyBlock := false
for selectedChildIterator.Next() {
selectedChild := selectedChildIterator.Get()
selectedChildStatus, err := sm.blockStatusStore.Get(sm.databaseContext, selectedChild)
hasBlock, err := sm.blockStore.HasBlock(sm.databaseContext, selectedChild)
if err != nil {
return nil, err
}
if selectedChildStatus == externalapi.StatusHeaderOnly {
if !hasBlock {
foundHeaderOnlyBlock = true
break
}
@@ -167,24 +170,3 @@ func (sm *syncManager) isHeaderOnlyBlock(blockHash *externalapi.DomainHash) (boo
return status == externalapi.StatusHeaderOnly, nil
}
func (sm *syncManager) isBlockInHeaderPruningPointFuture(blockHash *externalapi.DomainHash) (bool, error) {
if *blockHash == *sm.genesisBlockHash {
return false, nil
}
exists, err := sm.blockStatusStore.Exists(sm.databaseContext, blockHash)
if err != nil {
return false, err
}
if !exists {
return false, nil
}
headerTipsPruningPoint, err := sm.consensusStateManager.HeaderTipsPruningPoint()
if err != nil {
return false, err
}
return sm.dagTopologyManager.IsAncestorOf(headerTipsPruningPoint, blockHash)
}

View File

@@ -4,84 +4,43 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
)
// areHeaderTipsSyncedMaxTimeDifference is the number of blocks from
// the header virtual selected parent (estimated by timestamps) for
// kaspad to be considered not synced
const areHeaderTipsSyncedMaxTimeDifference = 300 // 5 minutes
func (sm *syncManager) syncInfo() (*externalapi.SyncInfo, error) {
syncState, err := sm.resolveSyncState()
isAwaitingUTXOSet, ibdRootUTXOBlockHash, err := sm.isAwaitingUTXOSet()
if err != nil {
return nil, err
}
var ibdRootUTXOBlockHash *externalapi.DomainHash
if syncState == externalapi.SyncStateAwaitingUTXOSet {
ibdRootUTXOBlockHash, err = sm.consensusStateManager.HeaderTipsPruningPoint()
if err != nil {
return nil, err
}
}
headerCount := sm.getHeaderCount()
blockCount := sm.getBlockCount()
return &externalapi.SyncInfo{
State: syncState,
IsAwaitingUTXOSet: isAwaitingUTXOSet,
IBDRootUTXOBlockHash: ibdRootUTXOBlockHash,
HeaderCount: headerCount,
BlockCount: blockCount,
}, nil
}
func (sm *syncManager) resolveSyncState() (externalapi.SyncState, error) {
hasTips, err := sm.headerTipsStore.HasTips(sm.databaseContext)
func (sm *syncManager) isAwaitingUTXOSet() (isAwaitingUTXOSet bool, ibdRootUTXOBlockHash *externalapi.DomainHash,
err error) {
pruningPointByHeaders, err := sm.pruningManager.CalculatePruningPointByHeaderSelectedTip()
if err != nil {
return 0, err
}
if !hasTips {
return externalapi.SyncStateAwaitingGenesis, nil
return false, nil, err
}
headerVirtualSelectedParentHash, err := sm.headerVirtualSelectedParentHash()
pruningPoint, err := sm.pruningStore.PruningPoint(sm.databaseContext)
if err != nil {
return 0, err
}
headerVirtualSelectedParentStatus, err := sm.blockStatusStore.Get(sm.databaseContext, headerVirtualSelectedParentHash)
if err != nil {
return 0, err
}
if headerVirtualSelectedParentStatus != externalapi.StatusHeaderOnly {
return externalapi.SyncStateSynced, nil
return false, nil, err
}
// Once the header tips are synced, check the status of
// the pruning point from the point of view of the header
// tips. We check it against StatusValid (rather than
// StatusHeaderOnly) because once we do receive the
// UTXO set of said pruning point, the state is explicitly
// set to StatusValid.
headerTipsPruningPoint, err := sm.consensusStateManager.HeaderTipsPruningPoint()
if err != nil {
return 0, err
}
headerTipsPruningPointStatus, err := sm.blockStatusStore.Get(sm.databaseContext, headerTipsPruningPoint)
if err != nil {
return 0, err
}
if headerTipsPruningPointStatus != externalapi.StatusValid {
return externalapi.SyncStateAwaitingUTXOSet, nil
// If the pruning point by headers is different from the current point
// it means we need to request the new pruning point UTXO set.
if *pruningPoint != *pruningPointByHeaders {
return true, pruningPointByHeaders, nil
}
return externalapi.SyncStateAwaitingBlockBodies, nil
}
func (sm *syncManager) headerVirtualSelectedParentHash() (*externalapi.DomainHash, error) {
headerTips, err := sm.headerTipsStore.Tips(sm.databaseContext)
if err != nil {
return nil, err
}
return sm.ghostdagManager.ChooseSelectedParent(headerTips...)
return false, nil, nil
}
func (sm *syncManager) getHeaderCount() uint64 {

View File

@@ -7,53 +7,50 @@ import (
)
type syncManager struct {
databaseContext model.DBReader
genesisBlockHash *externalapi.DomainHash
targetTimePerBlock int64
databaseContext model.DBReader
genesisBlockHash *externalapi.DomainHash
dagTraversalManager model.DAGTraversalManager
dagTopologyManager model.DAGTopologyManager
ghostdagManager model.GHOSTDAGManager
consensusStateManager model.ConsensusStateManager
dagTraversalManager model.DAGTraversalManager
dagTopologyManager model.DAGTopologyManager
ghostdagManager model.GHOSTDAGManager
pruningManager model.PruningManager
ghostdagDataStore model.GHOSTDAGDataStore
blockStatusStore model.BlockStatusStore
blockHeaderStore model.BlockHeaderStore
headerTipsStore model.HeaderTipsStore
blockStore model.BlockStore
pruningStore model.PruningStore
}
// New instantiates a new SyncManager
func New(
databaseContext model.DBReader,
genesisBlockHash *externalapi.DomainHash,
targetTimePerBlock int64,
dagTraversalManager model.DAGTraversalManager,
dagTopologyManager model.DAGTopologyManager,
ghostdagManager model.GHOSTDAGManager,
consensusStateManager model.ConsensusStateManager,
pruningManager model.PruningManager,
ghostdagDataStore model.GHOSTDAGDataStore,
blockStatusStore model.BlockStatusStore,
blockHeaderStore model.BlockHeaderStore,
headerTipsStore model.HeaderTipsStore,
blockStore model.BlockStore) model.SyncManager {
blockStore model.BlockStore,
pruningStore model.PruningStore) model.SyncManager {
return &syncManager{
databaseContext: databaseContext,
genesisBlockHash: genesisBlockHash,
targetTimePerBlock: targetTimePerBlock,
databaseContext: databaseContext,
genesisBlockHash: genesisBlockHash,
dagTraversalManager: dagTraversalManager,
dagTopologyManager: dagTopologyManager,
ghostdagManager: ghostdagManager,
consensusStateManager: consensusStateManager,
dagTraversalManager: dagTraversalManager,
dagTopologyManager: dagTopologyManager,
ghostdagManager: ghostdagManager,
pruningManager: pruningManager,
ghostdagDataStore: ghostdagDataStore,
blockStatusStore: blockStatusStore,
blockHeaderStore: blockHeaderStore,
headerTipsStore: headerTipsStore,
blockStore: blockStore,
pruningStore: pruningStore,
}
}
@@ -71,13 +68,6 @@ func (sm *syncManager) GetMissingBlockBodyHashes(highHash *externalapi.DomainHas
return sm.missingBlockBodyHashes(highHash)
}
func (sm *syncManager) IsBlockInHeaderPruningPointFuture(blockHash *externalapi.DomainHash) (bool, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "IsBlockInHeaderPruningPointFuture")
defer onEnd()
return sm.isBlockInHeaderPruningPointFuture(blockHash)
}
func (sm *syncManager) CreateBlockLocator(lowHash, highHash *externalapi.DomainHash, limit uint32) (externalapi.BlockLocator, error) {
onEnd := logger.LogAndMeasureExecutionTime(log, "CreateBlockLocator")
defer onEnd()

View File

@@ -1,6 +1,8 @@
package transactionvalidator_test
import (
"testing"
"github.com/kaspanet/kaspad/domain/consensus"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
@@ -12,7 +14,6 @@ import (
"github.com/kaspanet/kaspad/domain/dagconfig"
"github.com/kaspanet/kaspad/util"
"github.com/pkg/errors"
"testing"
)
type txSubnetworkData struct {
@@ -28,7 +29,7 @@ func TestValidateTransactionInIsolation(t *testing.T) {
if err != nil {
t.Fatalf("Error setting up consensus: %+v", err)
}
defer teardown()
defer teardown(false)
tests := []struct {
name string

View File

@@ -44,6 +44,9 @@ var (
// range.
ErrUnexpectedDifficulty = newRuleError("ErrUnexpectedDifficulty")
// ErrInvalidPoW indicates that the block proof-of-work is invalid.
ErrInvalidPoW = newRuleError("ErrInvalidPoW")
// ErrHighHash indicates the block does not hash to a value which is
// lower than the required target difficultly.
ErrHighHash = newRuleError("ErrHighHash")
@@ -56,7 +59,7 @@ var (
// the expected value.
ErrBadUTXOCommitment = newRuleError("ErrBadUTXOCommitment")
// ErrInvalidSubnetwork indicates the subnetwork is now allowed.
// ErrInvalidSubnetwork indicates the subnetwork is not allowed.
ErrInvalidSubnetwork = newRuleError("ErrInvalidSubnetwork")
// ErrFinalityPointTimeTooOld indicates a block has a timestamp before the
@@ -237,6 +240,8 @@ var (
//ErrBlockIsTooMuchInTheFuture indicates that the block timestamp is too much in the future.
ErrBlockIsTooMuchInTheFuture = newRuleError("ErrBlockIsTooMuchInTheFuture")
ErrUnexpectedPruningPoint = newRuleError("ErrUnexpectedPruningPoint")
)
// RuleError identifies a rule violation. It is used to indicate that

View File

@@ -34,7 +34,7 @@ func (tc *testConsensus) BuildBlockWithParents(parentHashes []*externalapi.Domai
}
func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinbaseData *externalapi.DomainCoinbaseData,
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, error) {
transactions []*externalapi.DomainTransaction) (*externalapi.DomainHash, *externalapi.BlockInsertionResult, error) {
// Require write lock because BuildBlockWithParents stages temporary data
tc.lock.Lock()
@@ -42,15 +42,15 @@ func (tc *testConsensus) AddBlock(parentHashes []*externalapi.DomainHash, coinba
block, _, err := tc.testBlockBuilder.BuildBlockWithParents(parentHashes, coinbaseData, transactions)
if err != nil {
return nil, err
return nil, nil, err
}
err = tc.blockProcessor.ValidateAndInsertBlock(block)
blockInsertionResult, err := tc.blockProcessor.ValidateAndInsertBlock(block)
if err != nil {
return nil, err
return nil, nil, err
}
return consensushashing.BlockHash(block), nil
return consensushashing.BlockHash(block), blockInsertionResult, nil
}
func (tc *testConsensus) DiscardAllStores() {

View File

@@ -5,7 +5,7 @@ import (
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
)
func (tc *testConsensus) DatabaseContext() model.DBReader {
func (tc *testConsensus) DatabaseContext() model.DBManager {
return tc.databaseContext
}
@@ -37,8 +37,8 @@ func (tc *testConsensus) GHOSTDAGDataStore() model.GHOSTDAGDataStore {
return tc.ghostdagDataStore
}
func (tc *testConsensus) HeaderTipsStore() model.HeaderTipsStore {
return tc.headerTipsStore
func (tc *testConsensus) HeaderTipsStore() model.HeaderSelectedTipStore {
return tc.headersSelectedTipStore
}
func (tc *testConsensus) MultisetStore() model.MultisetStore {
@@ -93,7 +93,7 @@ func (tc *testConsensus) GHOSTDAGManager() model.GHOSTDAGManager {
return tc.ghostdagManager
}
func (tc *testConsensus) HeaderTipsManager() model.HeaderTipsManager {
func (tc *testConsensus) HeaderTipsManager() model.HeadersSelectedTipManager {
return tc.headerTipsManager
}

View File

@@ -188,5 +188,5 @@ func ReadElements(r io.Reader, elements ...interface{}) error {
// IsMalformedError returns whether the error indicates a malformed data source
func IsMalformedError(err error) bool {
return errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, errMalformed)
return errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) || errors.Is(err, errMalformed)
}

View File

@@ -10,8 +10,6 @@ import (
"github.com/pkg/errors"
)
const uint32Size = 4
// SerializeUTXO returns the byte-slice representation for given UTXOEntry-outpoint pair
func SerializeUTXO(entry externalapi.UTXOEntry, outpoint *externalapi.DomainOutpoint) ([]byte, error) {
w := &bytes.Buffer{}
@@ -71,12 +69,6 @@ func deserializeOutpoint(r io.Reader) (*externalapi.DomainOutpoint, error) {
return nil, err
}
indexBytes := make([]byte, uint32Size)
_, err = io.ReadFull(r, indexBytes)
if err != nil {
return nil, err
}
var index uint32
err = serialization.ReadElement(r, &index)
if err != nil {
@@ -113,19 +105,19 @@ func deserializeUTXOEntry(r io.Reader) (externalapi.UTXOEntry, error) {
var blockBlueScore uint64
var amount uint64
var isCoinbase bool
err := serialization.ReadElements(r, blockBlueScore, amount, isCoinbase)
err := serialization.ReadElements(r, &blockBlueScore, &amount, &isCoinbase)
if err != nil {
return nil, err
}
var scriptPubKeyLen int
err = serialization.ReadElement(r, scriptPubKeyLen)
var scriptPubKeyLen uint64
err = serialization.ReadElement(r, &scriptPubKeyLen)
if err != nil {
return nil, err
}
scriptPubKey := make([]byte, scriptPubKeyLen)
_, err = r.Read(scriptPubKey)
_, err = io.ReadFull(r, scriptPubKey)
if err != nil {
return nil, errors.WithStack(err)
}

View File

@@ -2,6 +2,7 @@ package utxo
import (
"encoding/hex"
"reflect"
"testing"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
@@ -30,3 +31,38 @@ func Benchmark_serializeUTXO(b *testing.B) {
}
}
}
func Test_serializeUTXO(t *testing.T) {
scriptPublicKey, err := hex.DecodeString("76a914ad06dd6ddee55cbca9a9e3713bd7587509a3056488ac")
if err != nil {
t.Fatalf("Error decoding scriptPublicKey string: %s", err)
}
entry := NewUTXOEntry(5000000000, scriptPublicKey, false, 1432432)
outpoint := &externalapi.DomainOutpoint{
TransactionID: externalapi.DomainTransactionID{
0x16, 0x5e, 0x38, 0xe8, 0xb3, 0x91, 0x45, 0x95,
0xd9, 0xc6, 0x41, 0xf3, 0xb8, 0xee, 0xc2, 0xf3,
0x46, 0x11, 0x89, 0x6b, 0x82, 0x1a, 0x68, 0x3b,
0x7a, 0x4e, 0xde, 0xfe, 0x2c, 0x00, 0x00, 0x00,
},
Index: 0xffffffff,
}
serialized, err := SerializeUTXO(entry, outpoint)
if err != nil {
t.Fatalf("SerializeUTXO: %+v", err)
}
deserializedEntry, deserializedOutpoint, err := DeserializeUTXO(serialized)
if err != nil {
return
}
if !reflect.DeepEqual(deserializedEntry, entry) {
t.Fatalf("deserialized entry is not equal to the original")
}
if !reflect.DeepEqual(deserializedOutpoint, outpoint) {
t.Fatalf("deserialized outpoint is not equal to the original")
}
}

View File

@@ -83,6 +83,11 @@ func (networkFlags *NetworkFlags) ResolveNetwork(parser *flags.Parser) error {
return errors.Errorf("Mainnet has not launched yet, use --testnet to run in testnet mode")
}
err := networkFlags.overrideDAGParams()
if err != nil {
return err
}
return nil
}

View File

@@ -54,6 +54,8 @@ var (
snvrLog = BackendLog.Logger("SNVR")
wsvcLog = BackendLog.Logger("WSVC")
reacLog = BackendLog.Logger("REAC")
prnmLog = BackendLog.Logger("PRNM")
blvlLog = BackendLog.Logger("BLVL")
)
// SubsystemTags is an enum of all sub system tags
@@ -85,7 +87,9 @@ var SubsystemTags = struct {
DNSS,
SNVR,
WSVC,
REAC string
REAC,
PRNM,
BLVL string
}{
ADXR: "ADXR",
AMGR: "AMGR",
@@ -115,6 +119,8 @@ var SubsystemTags = struct {
SNVR: "SNVR",
WSVC: "WSVC",
REAC: "REAC",
PRNM: "PRNM",
BLVL: "BLVL",
}
// subsystemLoggers maps each subsystem identifier to its associated logger.
@@ -147,6 +153,8 @@ var subsystemLoggers = map[string]*Logger{
SubsystemTags.SNVR: snvrLog,
SubsystemTags.WSVC: wsvcLog,
SubsystemTags.REAC: reacLog,
SubsystemTags.PRNM: prnmLog,
SubsystemTags.BLVL: blvlLog,
}
// InitLog attaches log file and error log file to the backend log.

View File

@@ -4383,8 +4383,8 @@ type AcceptedBlock struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
AcceptedTxIds []string `protobuf:"bytes,2,rep,name=acceptedTxIds,proto3" json:"acceptedTxIds,omitempty"`
Hash string `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
AcceptedTransactionIds []string `protobuf:"bytes,2,rep,name=acceptedTransactionIds,proto3" json:"acceptedTransactionIds,omitempty"`
}
func (x *AcceptedBlock) Reset() {
@@ -4426,9 +4426,9 @@ func (x *AcceptedBlock) GetHash() string {
return ""
}
func (x *AcceptedBlock) GetAcceptedTxIds() []string {
func (x *AcceptedBlock) GetAcceptedTransactionIds() []string {
if x != nil {
return x.AcceptedTxIds
return x.AcceptedTransactionIds
}
return nil
}
@@ -7016,287 +7016,288 @@ var file_messages_proto_rawDesc = []byte{
0x63, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c,
0x6f, 0x63, 0x6b, 0x52, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x73, 0x22, 0x49, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42,
0x63, 0x6b, 0x73, 0x22, 0x5b, 0x0a, 0x0d, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x42,
0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x63, 0x63, 0x65,
0x70, 0x74, 0x65, 0x64, 0x54, 0x78, 0x49, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x54, 0x78, 0x49, 0x64, 0x73, 0x22, 0x96,
0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73,
0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x22, 0x0a,
0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49,
0x64, 0x12, 0x44, 0x0a, 0x1d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61,
0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62,
0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0xac, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x42,
0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73,
0x68, 0x12, 0x47, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73,
0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72,
0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x56,
0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52,
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x99, 0x04, 0x0a, 0x10, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x68,
0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x36, 0x0a, 0x16, 0x61, 0x63, 0x63, 0x65,
0x70, 0x74, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49,
0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74,
0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x73,
0x22, 0x96, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68,
0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12,
0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0e, 0x68, 0x61, 0x73,
0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f,
0x74, 0x12, 0x32, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d,
0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d, 0x65, 0x72, 0x6b, 0x6c,
0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d,
0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x75,
0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x59, 0x0a,
0x16, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62,
0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61,
0x52, 0x16, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72,
0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65,
0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05,
0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e, 0x6f, 0x6e,
0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63,
0x75, 0x6c, 0x74, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66,
0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x61,
0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x65,
0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68,
0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64,
0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x26, 0x0a, 0x0e, 0x74, 0x72,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x18, 0x0e, 0x20, 0x03,
0x28, 0x09, 0x52, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49,
0x44, 0x73, 0x22, 0x8f, 0x04, 0x0a, 0x16, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a,
0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x78, 0x49,
0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20,
0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18,
0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x12,
0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18,
0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04,
0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64,
0x48, 0x61, 0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f,
0x61, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61,
0x64, 0x12, 0x5e, 0x0a, 0x18, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x0a, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e,
0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f,
0x73, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x18, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74,
0x73, 0x12, 0x61, 0x0a, 0x19, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x18, 0x0b,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62,
0x6f, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x19, 0x74, 0x72, 0x61, 0x6e, 0x73,
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x4f, 0x75, 0x74,
0x70, 0x75, 0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73,
0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61,
0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04,
0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x54,
0x69, 0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x54, 0x69, 0x6d, 0x65, 0x22, 0x9f, 0x01, 0x0a, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74,
0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x74, 0x78, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x49, 0x6e,
0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x75,
0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x32, 0x0a, 0x09, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
0x53, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x69, 0x67, 0x52,
0x09, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65,
0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65,
0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x2f, 0x0a, 0x09, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74,
0x53, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x03, 0x61, 0x73, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x68, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x68, 0x65, 0x78, 0x22, 0x89, 0x01, 0x0a, 0x18, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x4f, 0x75,
0x74, 0x70, 0x75, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e,
0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78,
0x12, 0x41, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79,
0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69,
0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x52,
0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62,
0x4b, 0x65, 0x79, 0x22, 0x66, 0x0a, 0x12, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62,
0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x6d,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x73, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x68,
0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x68, 0x65, 0x78, 0x12, 0x12, 0x0a,
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x41, 0x0a, 0x1b, 0x47,
0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75,
0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x22, 0x66,
0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a,
0x0a, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52,
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x79, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61,
0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61,
0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74,
0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x38, 0x0a, 0x17, 0x69, 0x6e, 0x63, 0x6c, 0x75,
0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61,
0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74,
0x61, 0x22, 0x94, 0x02, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x46, 0x72,
0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65,
0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65,
0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64,
0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73,
0x12, 0x41, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c,
0x6f, 0x63, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63,
0x6b, 0x52, 0x10, 0x61, 0x64, 0x64, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x73, 0x12, 0x47, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62,
0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
0x6b, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x1d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65,
0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x69, 0x6e, 0x63, 0x6c,
0x75, 0x64, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65,
0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0xac, 0x01, 0x0a, 0x17, 0x47, 0x65,
0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61,
0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48,
0x61, 0x73, 0x68, 0x12, 0x47, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62,
0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56,
0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x10, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x05,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f,
0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xe1, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74,
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68, 0x12, 0x2c,
0x0a, 0x11, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65,
0x78, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x69, 0x6e, 0x63, 0x6c, 0x75,
0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x78, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x17,
0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62,
0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x69,
0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f,
0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x44, 0x0a, 0x1d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,
0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62,
0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1d, 0x69,
0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0xd1, 0x01, 0x0a,
0x18, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x6c, 0x6f,
0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b,
0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x78, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x78, 0x65, 0x73, 0x12, 0x47, 0x0a, 0x10, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18,
0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72,
0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61,
0x74, 0x61, 0x52, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65,
0x44, 0x61, 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x22, 0x1d, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e,
0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22,
0x8c, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e,
0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01,
0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74,
0x12, 0x20, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18,
0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75,
0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52,
0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x1f,
0x0a, 0x1d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49, 0x6e, 0x66,
0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22,
0xc8, 0x02, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49,
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4e, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75,
0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43,
0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f,
0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65,
0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61, 0x73,
0x68, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x70, 0x48, 0x61,
0x73, 0x68, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63, 0x75, 0x6c,
0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63,
0x75, 0x6c, 0x74, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x70, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x64, 0x69,
0x61, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x70, 0x61,
0x73, 0x74, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x13,
0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73,
0x68, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x76, 0x69, 0x72, 0x74, 0x75,
0x61, 0x6c, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x2a,
0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x99, 0x04, 0x0a, 0x10, 0x42, 0x6c, 0x6f,
0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a,
0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73,
0x68, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
0x28, 0x05, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0e, 0x68,
0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x04, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52,
0x6f, 0x6f, 0x74, 0x12, 0x32, 0x0a, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49,
0x44, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28,
0x09, 0x52, 0x14, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x49, 0x44, 0x4d, 0x65, 0x72,
0x6b, 0x6c, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43,
0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0e, 0x75, 0x74, 0x78, 0x6f, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12,
0x59, 0x0a, 0x16, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65,
0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e,
0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61,
0x74, 0x61, 0x52, 0x16, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56,
0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69,
0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14,
0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6e,
0x6f, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x69, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x62, 0x69, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66,
0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x64, 0x69,
0x66, 0x66, 0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x61, 0x72, 0x65,
0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c,
0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x2e, 0x0a, 0x12,
0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61,
0x73, 0x68, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74,
0x65, 0x64, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x26, 0x0a, 0x0e,
0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x73, 0x18, 0x0e,
0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x49, 0x44, 0x73, 0x22, 0x8f, 0x04, 0x0a, 0x16, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12,
0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74,
0x78, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x76, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d,
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x54, 0x69, 0x6d,
0x65, 0x12, 0x22, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49,
0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77,
0x6f, 0x72, 0x6b, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x61, 0x73, 0x18, 0x07, 0x20, 0x01,
0x28, 0x04, 0x52, 0x03, 0x67, 0x61, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f,
0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61,
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79,
0x6c, 0x6f, 0x61, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c,
0x6f, 0x61, 0x64, 0x12, 0x5e, 0x0a, 0x18, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18,
0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72,
0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72,
0x62, 0x6f, 0x73, 0x65, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x18, 0x74, 0x72, 0x61, 0x6e, 0x73,
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x49, 0x6e, 0x70,
0x75, 0x74, 0x73, 0x12, 0x61, 0x0a, 0x19, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73,
0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69,
0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65,
0x72, 0x62, 0x6f, 0x73, 0x65, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x19, 0x74, 0x72, 0x61,
0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x4f,
0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48,
0x61, 0x73, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
0x48, 0x61, 0x73, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01,
0x28, 0x04, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x6c, 0x6f,
0x63, 0x6b, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x9f, 0x01, 0x0a, 0x17, 0x54, 0x72, 0x61, 0x6e, 0x73,
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x49, 0x6e, 0x70,
0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x78, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x74, 0x78, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x6f, 0x75, 0x74,
0x70, 0x75, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x32, 0x0a, 0x09, 0x73, 0x63, 0x72, 0x69,
0x70, 0x74, 0x53, 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x69,
0x67, 0x52, 0x09, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x53, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08,
0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08,
0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0x2f, 0x0a, 0x09, 0x53, 0x63, 0x72, 0x69,
0x70, 0x74, 0x53, 0x69, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x6d, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x61, 0x73, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x68, 0x65, 0x78, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x68, 0x65, 0x78, 0x22, 0x89, 0x01, 0x0a, 0x18, 0x54, 0x72,
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65,
0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05,
0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x69, 0x6e, 0x64,
0x65, 0x78, 0x12, 0x41, 0x0a, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b,
0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50, 0x75, 0x62, 0x4b, 0x65,
0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50,
0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x66, 0x0a, 0x12, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x50,
0x75, 0x62, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61,
0x73, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x61, 0x73, 0x6d, 0x12, 0x10, 0x0a,
0x03, 0x68, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x68, 0x65, 0x78, 0x12,
0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74,
0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x41, 0x0a,
0x1b, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x22, 0x0a, 0x0c,
0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x49, 0x64,
0x22, 0x66, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72,
0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x12, 0x1a, 0x0a, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01,
0x28, 0x04, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2a, 0x0a, 0x05,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f,
0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x79, 0x0a, 0x1f, 0x47, 0x65, 0x74, 0x43,
0x68, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73,
0x74, 0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x73, 0x74, 0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x38, 0x0a, 0x17, 0x69, 0x6e, 0x63,
0x6c, 0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65,
0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x17, 0x69, 0x6e, 0x63, 0x6c,
0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44,
0x61, 0x74, 0x61, 0x22, 0x94, 0x02, 0x0a, 0x20, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x69, 0x6e,
0x46, 0x72, 0x6f, 0x6d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x38, 0x0a, 0x17, 0x72, 0x65, 0x6d, 0x6f,
0x76, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73,
0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x72, 0x65, 0x6d, 0x6f, 0x76,
0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68,
0x65, 0x73, 0x12, 0x41, 0x0a, 0x10, 0x61, 0x64, 0x64, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e,
0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x6c,
0x6f, 0x63, 0x6b, 0x52, 0x10, 0x61, 0x64, 0x64, 0x65, 0x64, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42,
0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x12, 0x47, 0x0a, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65,
0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63,
0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x52, 0x10, 0x62, 0x6c,
0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2a,
0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72,
0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x55, 0x0a, 0x25, 0x52, 0x65,
0x73, 0x6f, 0x6c, 0x76, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e,
0x66, 0x6c, 0x69, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42,
0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11,
0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73,
0x68, 0x22, 0x54, 0x0a, 0x26, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x46, 0x69, 0x6e, 0x61,
0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65,
0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72,
0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x27, 0x0a, 0x25, 0x4e, 0x6f, 0x74, 0x69, 0x66,
0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63,
0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x22, 0x54, 0x0a, 0x26, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69,
0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72,
0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52,
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x55, 0x0a, 0x23, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69,
0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69,
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a,
0x12, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48,
0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x76, 0x69, 0x6f, 0x6c, 0x61,
0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0x5b, 0x0a,
0x2b, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63,
0x74, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x11,
0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73,
0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74,
0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0x18, 0x0a, 0x16, 0x53, 0x68,
0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x22, 0x45, 0x0a, 0x17, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45,
0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x70, 0x0a, 0x18, 0x47,
0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74,
0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72,
0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02,
0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x69,
0x73, 0x41, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
0x52, 0x0b, 0x69, 0x73, 0x41, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x61, 0x0a,
0x19, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x65,
0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07,
0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xe1, 0x01, 0x0a, 0x17, 0x47,
0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73,
0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6c, 0x6f, 0x77, 0x48, 0x61, 0x73, 0x68,
0x12, 0x2c, 0x0a, 0x11, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b,
0x48, 0x65, 0x78, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x69, 0x6e, 0x63,
0x6c, 0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x78, 0x65, 0x73, 0x12, 0x38,
0x0a, 0x17, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65,
0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
0x17, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72,
0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x44, 0x0a, 0x1d, 0x69, 0x6e, 0x63, 0x6c,
0x75, 0x64, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x65,
0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52,
0x1d, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x22, 0xd1,
0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x62,
0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09,
0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x1e, 0x0a,
0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x78, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x09, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x65, 0x78, 0x65, 0x73, 0x12, 0x47, 0x0a,
0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x44, 0x61, 0x74,
0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77,
0x69, 0x72, 0x65, 0x2e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65,
0x44, 0x61, 0x74, 0x61, 0x52, 0x10, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x65, 0x72, 0x62, 0x6f,
0x73, 0x65, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18,
0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69,
0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72,
0x6f, 0x72, 0x22, 0x1d, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f,
0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x22, 0x8c, 0x01, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f,
0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74,
0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43, 0x6f, 0x75,
0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x43,
0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x32, 0x50, 0x0a, 0x03, 0x50, 0x32, 0x50, 0x12, 0x49, 0x0a, 0x0d, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x77, 0x69, 0x72, 0x65, 0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4b,
0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00, 0x28, 0x01,
0x30, 0x01, 0x32, 0x50, 0x0a, 0x03, 0x52, 0x50, 0x43, 0x12, 0x49, 0x0a, 0x0d, 0x4d, 0x65, 0x73,
0x22, 0x1f, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61, 0x67, 0x49,
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x22, 0xc8, 0x02, 0x0a, 0x1e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x44, 0x61,
0x67, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x4e,
0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x77, 0x6f,
0x72, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x43,
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x62, 0x6c, 0x6f, 0x63,
0x6b, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72,
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x68, 0x65, 0x61,
0x64, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x70, 0x48,
0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x70,
0x48, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x69, 0x66, 0x66, 0x69, 0x63,
0x75, 0x6c, 0x74, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a, 0x64, 0x69, 0x66, 0x66,
0x69, 0x63, 0x75, 0x6c, 0x74, 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x70, 0x61, 0x73, 0x74, 0x4d, 0x65,
0x64, 0x69, 0x61, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e,
0x70, 0x61, 0x73, 0x74, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30,
0x0a, 0x13, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48,
0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x76, 0x69, 0x72,
0x74, 0x75, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x61, 0x73, 0x68, 0x65, 0x73,
0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43,
0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x55, 0x0a, 0x25,
0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43,
0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74,
0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x11, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48,
0x61, 0x73, 0x68, 0x22, 0x54, 0x0a, 0x26, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x46, 0x69,
0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a,
0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72,
0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x27, 0x0a, 0x25, 0x4e, 0x6f, 0x74,
0x69, 0x66, 0x79, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c,
0x69, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x22, 0x54, 0x0a, 0x26, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x46, 0x69, 0x6e, 0x61,
0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2a, 0x0a, 0x05,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f,
0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x55, 0x0a, 0x23, 0x46, 0x69, 0x6e, 0x61,
0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x4e, 0x6f, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
0x2e, 0x0a, 0x12, 0x76, 0x69, 0x6f, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63,
0x6b, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x76, 0x69, 0x6f,
0x6c, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22,
0x5b, 0x0a, 0x2b, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x43, 0x6f, 0x6e, 0x66, 0x6c,
0x69, 0x63, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x4e, 0x6f, 0x74, 0x69, 0x66,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2c,
0x0a, 0x11, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48,
0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x66, 0x69, 0x6e, 0x61, 0x6c,
0x69, 0x74, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x22, 0x18, 0x0a, 0x16,
0x53, 0x68, 0x75, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x45, 0x0a, 0x17, 0x53, 0x68, 0x75, 0x74, 0x44, 0x6f,
0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0xe8, 0x07, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x52, 0x50,
0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x70, 0x0a,
0x18, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61,
0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74,
0x61, 0x72, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74,
0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x20, 0x0a,
0x0b, 0x69, 0x73, 0x41, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01,
0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x41, 0x73, 0x63, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x22,
0x61, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07,
0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x68,
0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18,
0xe8, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69,
0x72, 0x65, 0x2e, 0x52, 0x50, 0x43, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x52, 0x05, 0x65, 0x72, 0x72,
0x6f, 0x72, 0x32, 0x50, 0x0a, 0x03, 0x50, 0x32, 0x50, 0x12, 0x49, 0x0a, 0x0d, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65,
0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x00,
0x28, 0x01, 0x30, 0x01, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x61, 0x73, 0x70,
0x61, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
0x28, 0x01, 0x30, 0x01, 0x32, 0x50, 0x0a, 0x03, 0x52, 0x50, 0x43, 0x12, 0x49, 0x0a, 0x0d, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69,
0x72, 0x65, 0x2e, 0x4b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x26, 0x5a, 0x24, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x61,
0x73, 0x70, 0x61, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x77, 0x69, 0x72, 0x65, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@@ -439,7 +439,7 @@ message ChainBlock{
message AcceptedBlock{
string hash = 1;
repeated string acceptedTxIds = 2;
repeated string acceptedTransactionIds = 2;
}
message GetBlockRequestMessage{

View File

@@ -68,8 +68,8 @@ func (x *ChainBlock) toAppMessage() (*appmessage.ChainBlock, error) {
acceptedBlocks := make([]*appmessage.AcceptedBlock, len(x.AcceptedBlocks))
for j, acceptedBlock := range x.AcceptedBlocks {
acceptedBlocks[j] = &appmessage.AcceptedBlock{
Hash: acceptedBlock.Hash,
AcceptedTxIDs: acceptedBlock.AcceptedTxIds,
Hash: acceptedBlock.Hash,
AcceptedTransactionIDs: acceptedBlock.AcceptedTransactionIds,
}
}
return &appmessage.ChainBlock{
@@ -82,8 +82,8 @@ func (x *ChainBlock) fromAppMessage(message *appmessage.ChainBlock) error {
acceptedBlocks := make([]*AcceptedBlock, len(message.AcceptedBlocks))
for j, acceptedBlock := range message.AcceptedBlocks {
acceptedBlocks[j] = &AcceptedBlock{
Hash: acceptedBlock.Hash,
AcceptedTxIds: acceptedBlock.AcceptedTxIDs,
Hash: acceptedBlock.Hash,
AcceptedTransactionIds: acceptedBlock.AcceptedTransactionIDs,
}
}
*x = ChainBlock{

View File

@@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs
const (
appMajor uint = 0
appMinor uint = 8
appPatch uint = 2
appPatch uint = 3
)
// appBuild is defined as a variable so it can be overridden during the build